Merge pull request #32382 from deepeshgarg007/subscription_process
fix: Move subscription process to hourly long queue
diff --git a/erpnext/accounts/doctype/pos_invoice/pos_invoice.json b/erpnext/accounts/doctype/pos_invoice/pos_invoice.json
index b126d57..6f8b382 100644
--- a/erpnext/accounts/doctype/pos_invoice/pos_invoice.json
+++ b/erpnext/accounts/doctype/pos_invoice/pos_invoice.json
@@ -1553,7 +1553,7 @@
"icon": "fa fa-file-text",
"is_submittable": 1,
"links": [],
- "modified": "2022-03-22 13:00:24.166684",
+ "modified": "2022-09-27 13:00:24.166684",
"modified_by": "Administrator",
"module": "Accounts",
"name": "POS Invoice",
diff --git a/erpnext/accounts/doctype/pos_invoice/pos_invoice.py b/erpnext/accounts/doctype/pos_invoice/pos_invoice.py
index 6e3a076..9eded8a 100644
--- a/erpnext/accounts/doctype/pos_invoice/pos_invoice.py
+++ b/erpnext/accounts/doctype/pos_invoice/pos_invoice.py
@@ -740,3 +740,7 @@
]:
payment_mode = get_mode_of_payment_info(mode_of_payment, doc.company)
append_payment(payment_mode[0])
+
+
+def on_doctype_update():
+ frappe.db.add_index("POS Invoice", ["return_against"])
diff --git a/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py b/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py
index 0a4f25b..f901257 100644
--- a/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py
+++ b/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py
@@ -1543,6 +1543,37 @@
pi.save()
self.assertEqual(pi.items[0].conversion_factor, 1000)
+ def test_batch_expiry_for_purchase_invoice(self):
+ from erpnext.controllers.sales_and_purchase_return import make_return_doc
+
+ item = self.make_item(
+ "_Test Batch Item For Return Check",
+ {
+ "is_purchase_item": 1,
+ "is_stock_item": 1,
+ "has_batch_no": 1,
+ "create_new_batch": 1,
+ "batch_number_series": "TBIRC.#####",
+ },
+ )
+
+ pi = make_purchase_invoice(
+ qty=1,
+ item_code=item.name,
+ update_stock=True,
+ )
+
+ pi.load_from_db()
+ batch_no = pi.items[0].batch_no
+ self.assertTrue(batch_no)
+
+ frappe.db.set_value("Batch", batch_no, "expiry_date", add_days(nowdate(), -1))
+
+ return_pi = make_return_doc(pi.doctype, pi.name)
+ return_pi.save().submit()
+
+ self.assertTrue(return_pi.docstatus == 1)
+
def check_gl_entries(doc, voucher_no, expected_gle, posting_date):
gl_entries = frappe.db.sql(
diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py
index e51938b..94db9a9 100644
--- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py
+++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py
@@ -1081,7 +1081,7 @@
if self.is_return:
fixed_asset_gl_entries = get_gl_entries_on_asset_regain(
- asset, item.base_net_amount, item.finance_book
+ asset, item.base_net_amount, item.finance_book, self.get("doctype"), self.get("name")
)
asset.db_set("disposal_date", None)
@@ -1091,7 +1091,7 @@
else:
fixed_asset_gl_entries = get_gl_entries_on_asset_disposal(
- asset, item.base_net_amount, item.finance_book
+ asset, item.base_net_amount, item.finance_book, self.get("doctype"), self.get("name")
)
asset.db_set("disposal_date", self.posting_date)
diff --git a/erpnext/assets/doctype/asset/asset.js b/erpnext/assets/doctype/asset/asset.js
index a43a16c..5512d41 100644
--- a/erpnext/assets/doctype/asset/asset.js
+++ b/erpnext/assets/doctype/asset/asset.js
@@ -230,7 +230,7 @@
datasets: [{
color: 'green',
values: asset_values,
- formatted: asset_values.map(d => d.toFixed(2))
+ formatted: asset_values.map(d => d?.toFixed(2))
}]
},
type: 'line'
diff --git a/erpnext/assets/doctype/asset/depreciation.py b/erpnext/assets/doctype/asset/depreciation.py
index 7438638..a4bb960 100644
--- a/erpnext/assets/doctype/asset/depreciation.py
+++ b/erpnext/assets/doctype/asset/depreciation.py
@@ -235,7 +235,9 @@
asset.set_status()
-def get_gl_entries_on_asset_regain(asset, selling_amount=0, finance_book=None):
+def get_gl_entries_on_asset_regain(
+ asset, selling_amount=0, finance_book=None, voucher_type=None, voucher_no=None
+):
(
fixed_asset_account,
asset,
@@ -247,28 +249,45 @@
) = get_asset_details(asset, finance_book)
gl_entries = [
- {
- "account": fixed_asset_account,
- "debit_in_account_currency": asset.gross_purchase_amount,
- "debit": asset.gross_purchase_amount,
- "cost_center": depreciation_cost_center,
- },
- {
- "account": accumulated_depr_account,
- "credit_in_account_currency": accumulated_depr_amount,
- "credit": accumulated_depr_amount,
- "cost_center": depreciation_cost_center,
- },
+ asset.get_gl_dict(
+ {
+ "account": fixed_asset_account,
+ "debit_in_account_currency": asset.gross_purchase_amount,
+ "debit": asset.gross_purchase_amount,
+ "cost_center": depreciation_cost_center,
+ "posting_date": getdate(),
+ },
+ item=asset,
+ ),
+ asset.get_gl_dict(
+ {
+ "account": accumulated_depr_account,
+ "credit_in_account_currency": accumulated_depr_amount,
+ "credit": accumulated_depr_amount,
+ "cost_center": depreciation_cost_center,
+ "posting_date": getdate(),
+ },
+ item=asset,
+ ),
]
profit_amount = abs(flt(value_after_depreciation)) - abs(flt(selling_amount))
if profit_amount:
- get_profit_gl_entries(profit_amount, gl_entries, disposal_account, depreciation_cost_center)
+ get_profit_gl_entries(
+ asset, profit_amount, gl_entries, disposal_account, depreciation_cost_center
+ )
+
+ if voucher_type and voucher_no:
+ for entry in gl_entries:
+ entry["voucher_type"] = voucher_type
+ entry["voucher_no"] = voucher_no
return gl_entries
-def get_gl_entries_on_asset_disposal(asset, selling_amount=0, finance_book=None):
+def get_gl_entries_on_asset_disposal(
+ asset, selling_amount=0, finance_book=None, voucher_type=None, voucher_no=None
+):
(
fixed_asset_account,
asset,
@@ -280,23 +299,38 @@
) = get_asset_details(asset, finance_book)
gl_entries = [
- {
- "account": fixed_asset_account,
- "credit_in_account_currency": asset.gross_purchase_amount,
- "credit": asset.gross_purchase_amount,
- "cost_center": depreciation_cost_center,
- },
- {
- "account": accumulated_depr_account,
- "debit_in_account_currency": accumulated_depr_amount,
- "debit": accumulated_depr_amount,
- "cost_center": depreciation_cost_center,
- },
+ asset.get_gl_dict(
+ {
+ "account": fixed_asset_account,
+ "credit_in_account_currency": asset.gross_purchase_amount,
+ "credit": asset.gross_purchase_amount,
+ "cost_center": depreciation_cost_center,
+ "posting_date": getdate(),
+ },
+ item=asset,
+ ),
+ asset.get_gl_dict(
+ {
+ "account": accumulated_depr_account,
+ "debit_in_account_currency": accumulated_depr_amount,
+ "debit": accumulated_depr_amount,
+ "cost_center": depreciation_cost_center,
+ "posting_date": getdate(),
+ },
+ item=asset,
+ ),
]
profit_amount = flt(selling_amount) - flt(value_after_depreciation)
if profit_amount:
- get_profit_gl_entries(profit_amount, gl_entries, disposal_account, depreciation_cost_center)
+ get_profit_gl_entries(
+ asset, profit_amount, gl_entries, disposal_account, depreciation_cost_center
+ )
+
+ if voucher_type and voucher_no:
+ for entry in gl_entries:
+ entry["voucher_type"] = voucher_type
+ entry["voucher_no"] = voucher_no
return gl_entries
@@ -333,15 +367,21 @@
)
-def get_profit_gl_entries(profit_amount, gl_entries, disposal_account, depreciation_cost_center):
+def get_profit_gl_entries(
+ asset, profit_amount, gl_entries, disposal_account, depreciation_cost_center
+):
debit_or_credit = "debit" if profit_amount < 0 else "credit"
gl_entries.append(
- {
- "account": disposal_account,
- "cost_center": depreciation_cost_center,
- debit_or_credit: abs(profit_amount),
- debit_or_credit + "_in_account_currency": abs(profit_amount),
- }
+ asset.get_gl_dict(
+ {
+ "account": disposal_account,
+ "cost_center": depreciation_cost_center,
+ debit_or_credit: abs(profit_amount),
+ debit_or_credit + "_in_account_currency": abs(profit_amount),
+ "posting_date": getdate(),
+ },
+ item=asset,
+ )
)
diff --git a/erpnext/assets/doctype/asset_capitalization/asset_capitalization.py b/erpnext/assets/doctype/asset_capitalization/asset_capitalization.py
index 2e6f0ad..93194c0 100644
--- a/erpnext/assets/doctype/asset_capitalization/asset_capitalization.py
+++ b/erpnext/assets/doctype/asset_capitalization/asset_capitalization.py
@@ -428,7 +428,11 @@
asset.reload()
fixed_asset_gl_entries = get_gl_entries_on_asset_disposal(
- asset, item.asset_value, item.get("finance_book") or self.get("finance_book")
+ asset,
+ item.asset_value,
+ item.get("finance_book") or self.get("finance_book"),
+ self.get("doctype"),
+ self.get("name"),
)
asset.db_set("disposal_date", self.posting_date)
diff --git a/erpnext/manufacturing/doctype/work_order/work_order.js b/erpnext/manufacturing/doctype/work_order/work_order.js
index 20f1503..f3640b9 100644
--- a/erpnext/manufacturing/doctype/work_order/work_order.js
+++ b/erpnext/manufacturing/doctype/work_order/work_order.js
@@ -557,37 +557,52 @@
if(!frm.doc.skip_transfer){
// If "Material Consumption is check in Manufacturing Settings, allow Material Consumption
- if ((flt(doc.produced_qty) < flt(doc.material_transferred_for_manufacturing))
- && frm.doc.status != 'Stopped') {
- frm.has_finish_btn = true;
+ if (flt(doc.material_transferred_for_manufacturing) > 0 && frm.doc.status != 'Stopped') {
+ if ((flt(doc.produced_qty) < flt(doc.material_transferred_for_manufacturing))) {
+ frm.has_finish_btn = true;
- if (frm.doc.__onload && frm.doc.__onload.material_consumption == 1) {
- // Only show "Material Consumption" when required_qty > consumed_qty
- var counter = 0;
- var tbl = frm.doc.required_items || [];
- var tbl_lenght = tbl.length;
- for (var i = 0, len = tbl_lenght; i < len; i++) {
- let wo_item_qty = frm.doc.required_items[i].transferred_qty || frm.doc.required_items[i].required_qty;
- if (flt(wo_item_qty) > flt(frm.doc.required_items[i].consumed_qty)) {
- counter += 1;
+ if (frm.doc.__onload && frm.doc.__onload.material_consumption == 1) {
+ // Only show "Material Consumption" when required_qty > consumed_qty
+ var counter = 0;
+ var tbl = frm.doc.required_items || [];
+ var tbl_lenght = tbl.length;
+ for (var i = 0, len = tbl_lenght; i < len; i++) {
+ let wo_item_qty = frm.doc.required_items[i].transferred_qty || frm.doc.required_items[i].required_qty;
+ if (flt(wo_item_qty) > flt(frm.doc.required_items[i].consumed_qty)) {
+ counter += 1;
+ }
+ }
+ if (counter > 0) {
+ var consumption_btn = frm.add_custom_button(__('Material Consumption'), function() {
+ const backflush_raw_materials_based_on = frm.doc.__onload.backflush_raw_materials_based_on;
+ erpnext.work_order.make_consumption_se(frm, backflush_raw_materials_based_on);
+ });
+ consumption_btn.addClass('btn-primary');
}
}
- if (counter > 0) {
- var consumption_btn = frm.add_custom_button(__('Material Consumption'), function() {
- const backflush_raw_materials_based_on = frm.doc.__onload.backflush_raw_materials_based_on;
- erpnext.work_order.make_consumption_se(frm, backflush_raw_materials_based_on);
- });
- consumption_btn.addClass('btn-primary');
+
+ var finish_btn = frm.add_custom_button(__('Finish'), function() {
+ erpnext.work_order.make_se(frm, 'Manufacture');
+ });
+
+ if(doc.material_transferred_for_manufacturing>=doc.qty) {
+ // all materials transferred for manufacturing, make this primary
+ finish_btn.addClass('btn-primary');
}
- }
+ } else {
+ frappe.db.get_doc("Manufacturing Settings").then((doc) => {
+ let allowance_percentage = doc.overproduction_percentage_for_work_order;
- var finish_btn = frm.add_custom_button(__('Finish'), function() {
- erpnext.work_order.make_se(frm, 'Manufacture');
- });
+ if (allowance_percentage > 0) {
+ let allowed_qty = frm.doc.qty + ((allowance_percentage / 100) * frm.doc.qty);
- if(doc.material_transferred_for_manufacturing>=doc.qty) {
- // all materials transferred for manufacturing, make this primary
- finish_btn.addClass('btn-primary');
+ if ((flt(doc.produced_qty) < allowed_qty)) {
+ frm.add_custom_button(__('Finish'), function() {
+ erpnext.work_order.make_se(frm, 'Manufacture');
+ });
+ }
+ }
+ });
}
}
} else {
diff --git a/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py b/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py
index b77c3a5..6269724 100644
--- a/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py
+++ b/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py
@@ -1241,6 +1241,37 @@
self.assertEqual(query[0].value, 0)
+ def test_batch_expiry_for_purchase_receipt(self):
+ from erpnext.controllers.sales_and_purchase_return import make_return_doc
+
+ item = make_item(
+ "_Test Batch Item For Return Check",
+ {
+ "is_purchase_item": 1,
+ "is_stock_item": 1,
+ "has_batch_no": 1,
+ "create_new_batch": 1,
+ "batch_number_series": "TBIRC.#####",
+ },
+ )
+
+ pi = make_purchase_receipt(
+ qty=1,
+ item_code=item.name,
+ update_stock=True,
+ )
+
+ pi.load_from_db()
+ batch_no = pi.items[0].batch_no
+ self.assertTrue(batch_no)
+
+ frappe.db.set_value("Batch", batch_no, "expiry_date", add_days(today(), -1))
+
+ return_pi = make_return_doc(pi.doctype, pi.name)
+ return_pi.save().submit()
+
+ self.assertTrue(return_pi.docstatus == 1)
+
def prepare_data_for_internal_transfer():
from erpnext.accounts.doctype.sales_invoice.test_sales_invoice import create_internal_supplier
diff --git a/erpnext/stock/doctype/stock_entry/stock_entry.py b/erpnext/stock/doctype/stock_entry/stock_entry.py
index 738ac33..8bcd772 100644
--- a/erpnext/stock/doctype/stock_entry/stock_entry.py
+++ b/erpnext/stock/doctype/stock_entry/stock_entry.py
@@ -1073,8 +1073,8 @@
# No work order could mean independent Manufacture entry, if so skip validation
if self.work_order and self.fg_completed_qty > allowed_qty:
frappe.throw(
- _("For quantity {0} should not be greater than work order quantity {1}").format(
- flt(self.fg_completed_qty), wo_qty
+ _("For quantity {0} should not be greater than allowed quantity {1}").format(
+ flt(self.fg_completed_qty), allowed_qty
)
)
diff --git a/erpnext/stock/doctype/stock_ledger_entry/stock_ledger_entry.py b/erpnext/stock/doctype/stock_ledger_entry/stock_ledger_entry.py
index 329cd7d..f7f8cbe 100644
--- a/erpnext/stock/doctype/stock_ledger_entry/stock_ledger_entry.py
+++ b/erpnext/stock/doctype/stock_ledger_entry/stock_ledger_entry.py
@@ -153,6 +153,9 @@
def validate_batch(self):
if self.batch_no and self.voucher_type != "Stock Entry":
+ if self.voucher_type in ["Purchase Receipt", "Purchase Invoice"] and self.actual_qty < 0:
+ return
+
expiry_date = frappe.db.get_value("Batch", self.batch_no, "expiry_date")
if expiry_date:
if getdate(self.posting_date) > getdate(expiry_date):