frappe / erpnext

Free and Open Source Enterprise Resource Planning (ERP)
https://erpnext.com
GNU General Public License v3.0
20.23k stars 7.07k forks source link

Can't Cancel Stock Reconciliation error TypeError: unsupported operand type(s) for +=: 'NoneType' and 'NoneType' #42281

Open Ubaid-AI opened 2 months ago

Ubaid-AI commented 2 months ago

App Versions

{
    "erpnext": "14.70.2",
    "erpnext_pk": "0.0.1",
    "frappe": "14.75.0",
    "hrms": "16.0.0-dev",
    "ne_theme": "0.0.1",
    "payments": "0.0.1"
}

Route

Form/Stock Reconciliation/MAT-RECO-2024-00007

Traceback

Traceback (most recent call last):
  File "apps/frappe/frappe/app.py", line 97, in application
    response = frappe.api.handle()
  File "apps/frappe/frappe/api.py", line 55, in handle
    return frappe.handler.handle()
  File "apps/frappe/frappe/handler.py", line 48, in handle
    data = execute_cmd(cmd)
  File "apps/frappe/frappe/handler.py", line 86, in execute_cmd
    return frappe.call(method, **frappe.form_dict)
  File "apps/frappe/frappe/__init__.py", line 1619, in call
    return fn(*args, **newargs)
  File "apps/frappe/frappe/desk/form/save.py", line 50, in cancel
    doc.cancel()
  File "apps/erpnext/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.py", line 629, in cancel
    self._cancel()
  File "apps/frappe/frappe/model/document.py", line 1005, in _cancel
    return self.save()
  File "apps/frappe/frappe/model/document.py", line 310, in save
    return self._save(*args, **kwargs)
  File "apps/frappe/frappe/model/document.py", line 362, in _save
    self.run_post_save_methods()
  File "apps/frappe/frappe/model/document.py", line 1103, in run_post_save_methods
    self.run_method("on_cancel")
  File "apps/frappe/frappe/model/document.py", line 931, in run_method
    out = Document.hook(fn)(self, *args, **kwargs)
  File "apps/frappe/frappe/model/document.py", line 1283, in composer
    return composed(self, method, *args, **kwargs)
  File "apps/frappe/frappe/model/document.py", line 1265, in runner
    add_to_return_value(self, fn(self, *args, **kwargs))
  File "apps/frappe/frappe/model/document.py", line 928, in fn
    return method_object(*args, **kwargs)
  File "apps/erpnext/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.py", line 75, in on_cancel
    self.make_sle_on_cancel()
  File "apps/erpnext/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.py", line 523, in make_sle_on_cancel
    sl_entries = self.merge_similar_item_serial_nos(sl_entries)
  File "apps/erpnext/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.py", line 545, in merge_similar_item_serial_nos
    data.qty_after_transaction += d.qty_after_transaction
TypeError: unsupported operand type(s) for +=: 'NoneType' and 'NoneType'

Request Data

{
    "type": "POST",
    "args": {
        "doctype": "Stock Reconciliation",
        "name": "MAT-RECO-2024-00007"
    },
    "btn": {
        "jQuery360076095390770265771": {
            "events": {
                "click": [
                    {
                        "type": "click",
                        "origType": "click",
                        "guid": 3501,
                        "namespace": ""
                    }
                ]
            }
        }
    },
    "freeze": true,
    "headers": {},
    "error_handlers": {},
    "url": "/api/method/frappe.desk.form.save.cancel"
}

Response Data

{
    "exception": "TypeError: unsupported operand type(s) for +=: 'NoneType' and 'NoneType'"
}
Ubaid-AI commented 2 months ago

i modified the function in File "apps/erpnext/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.py" and its working fine for now

def merge_similar_item_serial_nos(self, sl_entries):

If user has put the same item in multiple row with different serial no

    new_sl_entries = []
    merge_similar_entries = {}

    for d in sl_entries:
        if not d.serial_no or flt(d.get("actual_qty")) < 0:
            new_sl_entries.append(d)
            continue

        key = (d.item_code, d.warehouse)
        if key not in merge_similar_entries:
            d.total_amount = flt(d.actual_qty) * d.valuation_rate
            merge_similar_entries[key] = d
        elif d.serial_no:
            data = merge_similar_entries[key]
            data.actual_qty += d.actual_qty
            d.qty_after_transaction = d.qty_after_transaction or 0
            data.qty_after_transaction = data.qty_after_transaction or 0
            data.qty_after_transaction += d.qty_after_transaction
            data.total_amount += d.actual_qty * d.valuation_rate
            if data.actual_qty != 0:
                data.valuation_rate = data.total_amount / data.actual_qty
                data.incoming_rate = data.total_amount / data.actual_qty
            else:
                data.valuation_rate = 0
                data.incoming_rate = 0
            data.serial_no += "\n" + d.serial_no

    new_sl_entries.extend(merge_similar_entries.values())
    return new_sl_entries