mirror of
https://github.com/frappe/erpnext.git
synced 2026-06-02 03:39:11 +00:00
Merge pull request #34327 from frappe/version-14-hotfix
chore: release v14
This commit is contained in:
@@ -137,7 +137,8 @@
|
|||||||
"fieldname": "finance_book",
|
"fieldname": "finance_book",
|
||||||
"fieldtype": "Link",
|
"fieldtype": "Link",
|
||||||
"label": "Finance Book",
|
"label": "Finance Book",
|
||||||
"options": "Finance Book"
|
"options": "Finance Book",
|
||||||
|
"read_only": 1
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"fieldname": "2_add_edit_gl_entries",
|
"fieldname": "2_add_edit_gl_entries",
|
||||||
@@ -538,7 +539,7 @@
|
|||||||
"idx": 176,
|
"idx": 176,
|
||||||
"is_submittable": 1,
|
"is_submittable": 1,
|
||||||
"links": [],
|
"links": [],
|
||||||
"modified": "2023-01-17 12:53:53.280620",
|
"modified": "2023-03-01 14:58:59.286591",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Accounts",
|
"module": "Accounts",
|
||||||
"name": "Journal Entry",
|
"name": "Journal Entry",
|
||||||
|
|||||||
@@ -495,26 +495,22 @@ def get_amount(ref_doc, payment_account=None):
|
|||||||
"""get amount based on doctype"""
|
"""get amount based on doctype"""
|
||||||
dt = ref_doc.doctype
|
dt = ref_doc.doctype
|
||||||
if dt in ["Sales Order", "Purchase Order"]:
|
if dt in ["Sales Order", "Purchase Order"]:
|
||||||
grand_total = flt(ref_doc.rounded_total) - flt(ref_doc.advance_paid)
|
grand_total = flt(ref_doc.rounded_total) or flt(ref_doc.grand_total)
|
||||||
|
|
||||||
elif dt in ["Sales Invoice", "Purchase Invoice"]:
|
elif dt in ["Sales Invoice", "Purchase Invoice"]:
|
||||||
if ref_doc.party_account_currency == ref_doc.currency:
|
if ref_doc.party_account_currency == ref_doc.currency:
|
||||||
grand_total = flt(ref_doc.outstanding_amount)
|
grand_total = flt(ref_doc.outstanding_amount)
|
||||||
else:
|
else:
|
||||||
grand_total = flt(ref_doc.outstanding_amount) / ref_doc.conversion_rate
|
grand_total = flt(ref_doc.outstanding_amount) / ref_doc.conversion_rate
|
||||||
|
|
||||||
elif dt == "POS Invoice":
|
elif dt == "POS Invoice":
|
||||||
for pay in ref_doc.payments:
|
for pay in ref_doc.payments:
|
||||||
if pay.type == "Phone" and pay.account == payment_account:
|
if pay.type == "Phone" and pay.account == payment_account:
|
||||||
grand_total = pay.amount
|
grand_total = pay.amount
|
||||||
break
|
break
|
||||||
|
|
||||||
elif dt == "Fees":
|
elif dt == "Fees":
|
||||||
grand_total = ref_doc.outstanding_amount
|
grand_total = ref_doc.outstanding_amount
|
||||||
|
|
||||||
if grand_total > 0:
|
if grand_total > 0:
|
||||||
return grand_total
|
return grand_total
|
||||||
|
|
||||||
else:
|
else:
|
||||||
frappe.throw(_("Payment Entry is already created"))
|
frappe.throw(_("Payment Entry is already created"))
|
||||||
|
|
||||||
|
|||||||
@@ -45,7 +45,10 @@ class TestPaymentRequest(unittest.TestCase):
|
|||||||
frappe.get_doc(method).insert(ignore_permissions=True)
|
frappe.get_doc(method).insert(ignore_permissions=True)
|
||||||
|
|
||||||
def test_payment_request_linkings(self):
|
def test_payment_request_linkings(self):
|
||||||
so_inr = make_sales_order(currency="INR")
|
so_inr = make_sales_order(currency="INR", do_not_save=True)
|
||||||
|
so_inr.disable_rounded_total = 1
|
||||||
|
so_inr.save()
|
||||||
|
|
||||||
pr = make_payment_request(
|
pr = make_payment_request(
|
||||||
dt="Sales Order",
|
dt="Sales Order",
|
||||||
dn=so_inr.name,
|
dn=so_inr.name,
|
||||||
|
|||||||
@@ -1485,11 +1485,17 @@ class PurchaseInvoice(BuyingController):
|
|||||||
if po_details:
|
if po_details:
|
||||||
updated_pr += update_billed_amount_based_on_po(po_details, update_modified)
|
updated_pr += update_billed_amount_based_on_po(po_details, update_modified)
|
||||||
|
|
||||||
|
adjust_incoming_rate = frappe.db.get_single_value(
|
||||||
|
"Buying Settings", "set_landed_cost_based_on_purchase_invoice_rate"
|
||||||
|
)
|
||||||
|
|
||||||
for pr in set(updated_pr):
|
for pr in set(updated_pr):
|
||||||
from erpnext.stock.doctype.purchase_receipt.purchase_receipt import update_billing_percentage
|
from erpnext.stock.doctype.purchase_receipt.purchase_receipt import update_billing_percentage
|
||||||
|
|
||||||
pr_doc = frappe.get_doc("Purchase Receipt", pr)
|
pr_doc = frappe.get_doc("Purchase Receipt", pr)
|
||||||
update_billing_percentage(pr_doc, update_modified=update_modified)
|
update_billing_percentage(
|
||||||
|
pr_doc, update_modified=update_modified, adjust_incoming_rate=adjust_incoming_rate
|
||||||
|
)
|
||||||
|
|
||||||
def get_pr_details_billed_amt(self):
|
def get_pr_details_billed_amt(self):
|
||||||
# Get billed amount based on purchase receipt item reference (pr_detail) in purchase invoice
|
# Get billed amount based on purchase receipt item reference (pr_detail) in purchase invoice
|
||||||
|
|||||||
@@ -1523,6 +1523,94 @@ class TestPurchaseInvoice(unittest.TestCase, StockTestMixin):
|
|||||||
company.enable_provisional_accounting_for_non_stock_items = 0
|
company.enable_provisional_accounting_for_non_stock_items = 0
|
||||||
company.save()
|
company.save()
|
||||||
|
|
||||||
|
def test_adjust_incoming_rate(self):
|
||||||
|
frappe.db.set_single_value("Buying Settings", "maintain_same_rate", 0)
|
||||||
|
|
||||||
|
frappe.db.set_single_value(
|
||||||
|
"Buying Settings", "set_landed_cost_based_on_purchase_invoice_rate", 1
|
||||||
|
)
|
||||||
|
|
||||||
|
# Increase the cost of the item
|
||||||
|
|
||||||
|
pr = make_purchase_receipt(qty=1, rate=100)
|
||||||
|
|
||||||
|
stock_value_difference = frappe.db.get_value(
|
||||||
|
"Stock Ledger Entry",
|
||||||
|
{"voucher_type": "Purchase Receipt", "voucher_no": pr.name},
|
||||||
|
"stock_value_difference",
|
||||||
|
)
|
||||||
|
self.assertEqual(stock_value_difference, 100)
|
||||||
|
|
||||||
|
pi = create_purchase_invoice_from_receipt(pr.name)
|
||||||
|
for row in pi.items:
|
||||||
|
row.rate = 150
|
||||||
|
|
||||||
|
pi.save()
|
||||||
|
pi.submit()
|
||||||
|
|
||||||
|
stock_value_difference = frappe.db.get_value(
|
||||||
|
"Stock Ledger Entry",
|
||||||
|
{"voucher_type": "Purchase Receipt", "voucher_no": pr.name},
|
||||||
|
"stock_value_difference",
|
||||||
|
)
|
||||||
|
self.assertEqual(stock_value_difference, 150)
|
||||||
|
|
||||||
|
# Reduce the cost of the item
|
||||||
|
|
||||||
|
pr = make_purchase_receipt(qty=1, rate=100)
|
||||||
|
|
||||||
|
stock_value_difference = frappe.db.get_value(
|
||||||
|
"Stock Ledger Entry",
|
||||||
|
{"voucher_type": "Purchase Receipt", "voucher_no": pr.name},
|
||||||
|
"stock_value_difference",
|
||||||
|
)
|
||||||
|
self.assertEqual(stock_value_difference, 100)
|
||||||
|
|
||||||
|
pi = create_purchase_invoice_from_receipt(pr.name)
|
||||||
|
for row in pi.items:
|
||||||
|
row.rate = 50
|
||||||
|
|
||||||
|
pi.save()
|
||||||
|
pi.submit()
|
||||||
|
|
||||||
|
stock_value_difference = frappe.db.get_value(
|
||||||
|
"Stock Ledger Entry",
|
||||||
|
{"voucher_type": "Purchase Receipt", "voucher_no": pr.name},
|
||||||
|
"stock_value_difference",
|
||||||
|
)
|
||||||
|
self.assertEqual(stock_value_difference, 50)
|
||||||
|
|
||||||
|
frappe.db.set_single_value(
|
||||||
|
"Buying Settings", "set_landed_cost_based_on_purchase_invoice_rate", 0
|
||||||
|
)
|
||||||
|
|
||||||
|
# Don't adjust incoming rate
|
||||||
|
|
||||||
|
pr = make_purchase_receipt(qty=1, rate=100)
|
||||||
|
|
||||||
|
stock_value_difference = frappe.db.get_value(
|
||||||
|
"Stock Ledger Entry",
|
||||||
|
{"voucher_type": "Purchase Receipt", "voucher_no": pr.name},
|
||||||
|
"stock_value_difference",
|
||||||
|
)
|
||||||
|
self.assertEqual(stock_value_difference, 100)
|
||||||
|
|
||||||
|
pi = create_purchase_invoice_from_receipt(pr.name)
|
||||||
|
for row in pi.items:
|
||||||
|
row.rate = 50
|
||||||
|
|
||||||
|
pi.save()
|
||||||
|
pi.submit()
|
||||||
|
|
||||||
|
stock_value_difference = frappe.db.get_value(
|
||||||
|
"Stock Ledger Entry",
|
||||||
|
{"voucher_type": "Purchase Receipt", "voucher_no": pr.name},
|
||||||
|
"stock_value_difference",
|
||||||
|
)
|
||||||
|
self.assertEqual(stock_value_difference, 100)
|
||||||
|
|
||||||
|
frappe.db.set_single_value("Buying Settings", "maintain_same_rate", 1)
|
||||||
|
|
||||||
def test_item_less_defaults(self):
|
def test_item_less_defaults(self):
|
||||||
|
|
||||||
pi = frappe.new_doc("Purchase Invoice")
|
pi = frappe.new_doc("Purchase Invoice")
|
||||||
|
|||||||
@@ -38,8 +38,11 @@
|
|||||||
{% if(data[i].posting_date) { %}
|
{% if(data[i].posting_date) { %}
|
||||||
<td>{%= frappe.datetime.str_to_user(data[i].posting_date) %}</td>
|
<td>{%= frappe.datetime.str_to_user(data[i].posting_date) %}</td>
|
||||||
<td>{%= data[i].voucher_type %}
|
<td>{%= data[i].voucher_type %}
|
||||||
<br>{%= data[i].voucher_no %}</td>
|
<br>{%= data[i].voucher_no %}
|
||||||
<td>
|
</td>
|
||||||
|
{% var longest_word = cstr(data[i].remarks).split(" ").reduce((longest, word) => word.length > longest.length ? word : longest, ""); %}
|
||||||
|
<td {% if longest_word.length > 45 %} class="overflow-wrap-anywhere" {% endif %}>
|
||||||
|
<span>
|
||||||
{% if(!(filters.party || filters.account)) { %}
|
{% if(!(filters.party || filters.account)) { %}
|
||||||
{%= data[i].party || data[i].account %}
|
{%= data[i].party || data[i].account %}
|
||||||
<br>
|
<br>
|
||||||
@@ -49,11 +52,14 @@
|
|||||||
{% if(data[i].bill_no) { %}
|
{% if(data[i].bill_no) { %}
|
||||||
<br>{%= __("Supplier Invoice No") %}: {%= data[i].bill_no %}
|
<br>{%= __("Supplier Invoice No") %}: {%= data[i].bill_no %}
|
||||||
{% } %}
|
{% } %}
|
||||||
</td>
|
</span>
|
||||||
<td style="text-align: right">
|
</td>
|
||||||
{%= format_currency(data[i].debit, filters.presentation_currency || data[i].account_currency) %}</td>
|
<td style="text-align: right">
|
||||||
<td style="text-align: right">
|
{%= format_currency(data[i].debit, filters.presentation_currency) %}
|
||||||
{%= format_currency(data[i].credit, filters.presentation_currency || data[i].account_currency) %}</td>
|
</td>
|
||||||
|
<td style="text-align: right">
|
||||||
|
{%= format_currency(data[i].credit, filters.presentation_currency) %}
|
||||||
|
</td>
|
||||||
{% } else { %}
|
{% } else { %}
|
||||||
<td></td>
|
<td></td>
|
||||||
<td></td>
|
<td></td>
|
||||||
|
|||||||
@@ -18,6 +18,7 @@
|
|||||||
"pr_required",
|
"pr_required",
|
||||||
"column_break_12",
|
"column_break_12",
|
||||||
"maintain_same_rate",
|
"maintain_same_rate",
|
||||||
|
"set_landed_cost_based_on_purchase_invoice_rate",
|
||||||
"allow_multiple_items",
|
"allow_multiple_items",
|
||||||
"bill_for_rejected_quantity_in_purchase_invoice",
|
"bill_for_rejected_quantity_in_purchase_invoice",
|
||||||
"disable_last_purchase_rate",
|
"disable_last_purchase_rate",
|
||||||
@@ -147,6 +148,14 @@
|
|||||||
"fieldname": "show_pay_button",
|
"fieldname": "show_pay_button",
|
||||||
"fieldtype": "Check",
|
"fieldtype": "Check",
|
||||||
"label": "Show Pay Button in Purchase Order Portal"
|
"label": "Show Pay Button in Purchase Order Portal"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"default": "0",
|
||||||
|
"depends_on": "eval: !doc.maintain_same_rate",
|
||||||
|
"description": "Users can enable the checkbox If they want to adjust the incoming rate (set using purchase receipt) based on the purchase invoice rate.",
|
||||||
|
"fieldname": "set_landed_cost_based_on_purchase_invoice_rate",
|
||||||
|
"fieldtype": "Check",
|
||||||
|
"label": "Set Landed Cost Based on Purchase Invoice Rate"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"icon": "fa fa-cog",
|
"icon": "fa fa-cog",
|
||||||
@@ -154,7 +163,7 @@
|
|||||||
"index_web_pages_for_search": 1,
|
"index_web_pages_for_search": 1,
|
||||||
"issingle": 1,
|
"issingle": 1,
|
||||||
"links": [],
|
"links": [],
|
||||||
"modified": "2023-02-15 14:42:10.200679",
|
"modified": "2023-02-28 15:41:32.686805",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Buying",
|
"module": "Buying",
|
||||||
"name": "Buying Settings",
|
"name": "Buying Settings",
|
||||||
|
|||||||
@@ -21,3 +21,10 @@ class BuyingSettings(Document):
|
|||||||
self.get("supp_master_name") == "Naming Series",
|
self.get("supp_master_name") == "Naming Series",
|
||||||
hide_name_field=False,
|
hide_name_field=False,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def before_save(self):
|
||||||
|
self.check_maintain_same_rate()
|
||||||
|
|
||||||
|
def check_maintain_same_rate(self):
|
||||||
|
if self.maintain_same_rate:
|
||||||
|
self.set_landed_cost_based_on_purchase_invoice_rate = 0
|
||||||
|
|||||||
@@ -269,7 +269,10 @@ class BuyingController(SubcontractingController):
|
|||||||
) / qty_in_stock_uom
|
) / qty_in_stock_uom
|
||||||
else:
|
else:
|
||||||
item.valuation_rate = (
|
item.valuation_rate = (
|
||||||
item.base_net_amount + item.item_tax_amount + flt(item.landed_cost_voucher_amount)
|
item.base_net_amount
|
||||||
|
+ item.item_tax_amount
|
||||||
|
+ flt(item.landed_cost_voucher_amount)
|
||||||
|
+ flt(item.get("rate_difference_with_purchase_invoice"))
|
||||||
) / qty_in_stock_uom
|
) / qty_in_stock_uom
|
||||||
else:
|
else:
|
||||||
item.valuation_rate = 0.0
|
item.valuation_rate = 0.0
|
||||||
|
|||||||
@@ -87,6 +87,9 @@ class SellingController(StockController):
|
|||||||
)
|
)
|
||||||
if not self.meta.get_field("sales_team"):
|
if not self.meta.get_field("sales_team"):
|
||||||
party_details.pop("sales_team")
|
party_details.pop("sales_team")
|
||||||
|
else:
|
||||||
|
self.set("sales_team", party_details.get("sales_team"))
|
||||||
|
|
||||||
self.update_if_missing(party_details)
|
self.update_if_missing(party_details)
|
||||||
|
|
||||||
elif lead:
|
elif lead:
|
||||||
@@ -139,7 +142,7 @@ class SellingController(StockController):
|
|||||||
self.in_words = money_in_words(amount, self.currency)
|
self.in_words = money_in_words(amount, self.currency)
|
||||||
|
|
||||||
def calculate_commission(self):
|
def calculate_commission(self):
|
||||||
if not self.meta.get_field("commission_rate"):
|
if not self.meta.get_field("commission_rate") or self.docstatus.is_submitted():
|
||||||
return
|
return
|
||||||
|
|
||||||
self.round_floats_in(self, ("amount_eligible_for_commission", "commission_rate"))
|
self.round_floats_in(self, ("amount_eligible_for_commission", "commission_rate"))
|
||||||
|
|||||||
@@ -368,7 +368,7 @@ auto_cancel_exempted_doctypes = [
|
|||||||
|
|
||||||
scheduler_events = {
|
scheduler_events = {
|
||||||
"cron": {
|
"cron": {
|
||||||
"0/5 * * * *": [
|
"0/15 * * * *": [
|
||||||
"erpnext.manufacturing.doctype.bom_update_log.bom_update_log.resume_bom_cost_update_jobs",
|
"erpnext.manufacturing.doctype.bom_update_log.bom_update_log.resume_bom_cost_update_jobs",
|
||||||
],
|
],
|
||||||
"0/30 * * * *": [
|
"0/30 * * * *": [
|
||||||
|
|||||||
@@ -212,7 +212,7 @@ def resume_bom_cost_update_jobs():
|
|||||||
["name", "boms_updated", "status"],
|
["name", "boms_updated", "status"],
|
||||||
)
|
)
|
||||||
incomplete_level = any(row.get("status") == "Pending" for row in bom_batches)
|
incomplete_level = any(row.get("status") == "Pending" for row in bom_batches)
|
||||||
if not bom_batches or incomplete_level:
|
if not bom_batches or not incomplete_level:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
# Prep parent BOMs & updated processed BOMs for next level
|
# Prep parent BOMs & updated processed BOMs for next level
|
||||||
@@ -252,6 +252,9 @@ def get_processed_current_boms(
|
|||||||
current_boms = []
|
current_boms = []
|
||||||
|
|
||||||
for row in bom_batches:
|
for row in bom_batches:
|
||||||
|
if not row.boms_updated:
|
||||||
|
continue
|
||||||
|
|
||||||
boms_updated = json.loads(row.boms_updated)
|
boms_updated = json.loads(row.boms_updated)
|
||||||
current_boms.extend(boms_updated)
|
current_boms.extend(boms_updated)
|
||||||
boms_updated_dict = {bom: True for bom in boms_updated}
|
boms_updated_dict = {bom: True for bom in boms_updated}
|
||||||
|
|||||||
@@ -488,7 +488,7 @@ erpnext.TransactionController = class TransactionController extends erpnext.taxe
|
|||||||
() => {
|
() => {
|
||||||
var d = locals[cdt][cdn];
|
var d = locals[cdt][cdn];
|
||||||
me.add_taxes_from_item_tax_template(d.item_tax_rate);
|
me.add_taxes_from_item_tax_template(d.item_tax_rate);
|
||||||
if (d.free_item_data) {
|
if (d.free_item_data && d.free_item_data.length > 0) {
|
||||||
me.apply_product_discount(d);
|
me.apply_product_discount(d);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -1884,11 +1884,13 @@ erpnext.TransactionController = class TransactionController extends erpnext.taxe
|
|||||||
|
|
||||||
get_advances() {
|
get_advances() {
|
||||||
if(!this.frm.is_return) {
|
if(!this.frm.is_return) {
|
||||||
|
var me = this;
|
||||||
return this.frm.call({
|
return this.frm.call({
|
||||||
method: "set_advances",
|
method: "set_advances",
|
||||||
doc: this.frm.doc,
|
doc: this.frm.doc,
|
||||||
callback: function(r, rt) {
|
callback: function(r, rt) {
|
||||||
refresh_field("advances");
|
refresh_field("advances");
|
||||||
|
me.frm.dirty();
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -253,7 +253,7 @@ erpnext.selling.SellingController = class SellingController extends erpnext.Tran
|
|||||||
}
|
}
|
||||||
|
|
||||||
calculate_commission() {
|
calculate_commission() {
|
||||||
if(!this.frm.fields_dict.commission_rate) return;
|
if(!this.frm.fields_dict.commission_rate || this.frm.doc.docstatus === 1) return;
|
||||||
|
|
||||||
if(this.frm.doc.commission_rate > 100) {
|
if(this.frm.doc.commission_rate > 100) {
|
||||||
this.frm.set_value("commission_rate", 100);
|
this.frm.set_value("commission_rate", 100);
|
||||||
|
|||||||
@@ -293,6 +293,7 @@ class PurchaseReceipt(BuyingController):
|
|||||||
get_purchase_document_details,
|
get_purchase_document_details,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
stock_rbnb = None
|
||||||
if erpnext.is_perpetual_inventory_enabled(self.company):
|
if erpnext.is_perpetual_inventory_enabled(self.company):
|
||||||
stock_rbnb = self.get_company_default("stock_received_but_not_billed")
|
stock_rbnb = self.get_company_default("stock_received_but_not_billed")
|
||||||
landed_cost_entries = get_item_account_wise_additional_cost(self.name)
|
landed_cost_entries = get_item_account_wise_additional_cost(self.name)
|
||||||
@@ -450,6 +451,21 @@ class PurchaseReceipt(BuyingController):
|
|||||||
item=d,
|
item=d,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if d.rate_difference_with_purchase_invoice and stock_rbnb:
|
||||||
|
account_currency = get_account_currency(stock_rbnb)
|
||||||
|
self.add_gl_entry(
|
||||||
|
gl_entries=gl_entries,
|
||||||
|
account=stock_rbnb,
|
||||||
|
cost_center=d.cost_center,
|
||||||
|
debit=0.0,
|
||||||
|
credit=flt(d.rate_difference_with_purchase_invoice),
|
||||||
|
remarks=_("Adjustment based on Purchase Invoice rate"),
|
||||||
|
against_account=warehouse_account_name,
|
||||||
|
account_currency=account_currency,
|
||||||
|
project=d.project,
|
||||||
|
item=d,
|
||||||
|
)
|
||||||
|
|
||||||
# sub-contracting warehouse
|
# sub-contracting warehouse
|
||||||
if flt(d.rm_supp_cost) and warehouse_account.get(self.supplier_warehouse):
|
if flt(d.rm_supp_cost) and warehouse_account.get(self.supplier_warehouse):
|
||||||
self.add_gl_entry(
|
self.add_gl_entry(
|
||||||
@@ -470,6 +486,7 @@ class PurchaseReceipt(BuyingController):
|
|||||||
+ flt(d.landed_cost_voucher_amount)
|
+ flt(d.landed_cost_voucher_amount)
|
||||||
+ flt(d.rm_supp_cost)
|
+ flt(d.rm_supp_cost)
|
||||||
+ flt(d.item_tax_amount)
|
+ flt(d.item_tax_amount)
|
||||||
|
+ flt(d.rate_difference_with_purchase_invoice)
|
||||||
)
|
)
|
||||||
|
|
||||||
divisional_loss = flt(
|
divisional_loss = flt(
|
||||||
@@ -765,7 +782,7 @@ class PurchaseReceipt(BuyingController):
|
|||||||
updated_pr += update_billed_amount_based_on_po(po_details, update_modified)
|
updated_pr += update_billed_amount_based_on_po(po_details, update_modified)
|
||||||
|
|
||||||
for pr in set(updated_pr):
|
for pr in set(updated_pr):
|
||||||
pr_doc = self if (pr == self.name) else frappe.get_cached_doc("Purchase Receipt", pr)
|
pr_doc = self if (pr == self.name) else frappe.get_doc("Purchase Receipt", pr)
|
||||||
update_billing_percentage(pr_doc, update_modified=update_modified)
|
update_billing_percentage(pr_doc, update_modified=update_modified)
|
||||||
|
|
||||||
self.load_from_db()
|
self.load_from_db()
|
||||||
@@ -881,7 +898,7 @@ def get_billed_amount_against_po(po_items):
|
|||||||
return {d.po_detail: flt(d.billed_amt) for d in query}
|
return {d.po_detail: flt(d.billed_amt) for d in query}
|
||||||
|
|
||||||
|
|
||||||
def update_billing_percentage(pr_doc, update_modified=True):
|
def update_billing_percentage(pr_doc, update_modified=True, adjust_incoming_rate=False):
|
||||||
# Reload as billed amount was set in db directly
|
# Reload as billed amount was set in db directly
|
||||||
pr_doc.load_from_db()
|
pr_doc.load_from_db()
|
||||||
|
|
||||||
@@ -897,6 +914,12 @@ def update_billing_percentage(pr_doc, update_modified=True):
|
|||||||
|
|
||||||
total_amount += total_billable_amount
|
total_amount += total_billable_amount
|
||||||
total_billed_amount += flt(item.billed_amt)
|
total_billed_amount += flt(item.billed_amt)
|
||||||
|
if adjust_incoming_rate:
|
||||||
|
adjusted_amt = 0.0
|
||||||
|
if item.billed_amt and item.amount:
|
||||||
|
adjusted_amt = flt(item.billed_amt) - flt(item.amount)
|
||||||
|
|
||||||
|
item.db_set("rate_difference_with_purchase_invoice", adjusted_amt, update_modified=False)
|
||||||
|
|
||||||
percent_billed = round(100 * (total_billed_amount / (total_amount or 1)), 6)
|
percent_billed = round(100 * (total_billed_amount / (total_amount or 1)), 6)
|
||||||
pr_doc.db_set("per_billed", percent_billed)
|
pr_doc.db_set("per_billed", percent_billed)
|
||||||
@@ -906,6 +929,26 @@ def update_billing_percentage(pr_doc, update_modified=True):
|
|||||||
pr_doc.set_status(update=True)
|
pr_doc.set_status(update=True)
|
||||||
pr_doc.notify_update()
|
pr_doc.notify_update()
|
||||||
|
|
||||||
|
if adjust_incoming_rate:
|
||||||
|
adjust_incoming_rate_for_pr(pr_doc)
|
||||||
|
|
||||||
|
|
||||||
|
def adjust_incoming_rate_for_pr(doc):
|
||||||
|
doc.update_valuation_rate(reset_outgoing_rate=False)
|
||||||
|
|
||||||
|
for item in doc.get("items"):
|
||||||
|
item.db_update()
|
||||||
|
|
||||||
|
doc.docstatus = 2
|
||||||
|
doc.update_stock_ledger(allow_negative_stock=True, via_landed_cost_voucher=True)
|
||||||
|
doc.make_gl_entries_on_cancel()
|
||||||
|
|
||||||
|
# update stock & gl entries for submit state of PR
|
||||||
|
doc.docstatus = 1
|
||||||
|
doc.update_stock_ledger(allow_negative_stock=True, via_landed_cost_voucher=True)
|
||||||
|
doc.make_gl_entries()
|
||||||
|
doc.repost_future_sle_and_gle()
|
||||||
|
|
||||||
|
|
||||||
def get_item_wise_returned_qty(pr_doc):
|
def get_item_wise_returned_qty(pr_doc):
|
||||||
items = [d.name for d in pr_doc.items]
|
items = [d.name for d in pr_doc.items]
|
||||||
|
|||||||
@@ -69,6 +69,7 @@
|
|||||||
"item_tax_amount",
|
"item_tax_amount",
|
||||||
"rm_supp_cost",
|
"rm_supp_cost",
|
||||||
"landed_cost_voucher_amount",
|
"landed_cost_voucher_amount",
|
||||||
|
"rate_difference_with_purchase_invoice",
|
||||||
"billed_amt",
|
"billed_amt",
|
||||||
"warehouse_and_reference",
|
"warehouse_and_reference",
|
||||||
"warehouse",
|
"warehouse",
|
||||||
@@ -1007,12 +1008,20 @@
|
|||||||
"fieldtype": "Check",
|
"fieldtype": "Check",
|
||||||
"label": "Has Item Scanned",
|
"label": "Has Item Scanned",
|
||||||
"read_only": 1
|
"read_only": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "rate_difference_with_purchase_invoice",
|
||||||
|
"fieldtype": "Currency",
|
||||||
|
"label": "Rate Difference with Purchase Invoice",
|
||||||
|
"no_copy": 1,
|
||||||
|
"print_hide": 1,
|
||||||
|
"read_only": 1
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"idx": 1,
|
"idx": 1,
|
||||||
"istable": 1,
|
"istable": 1,
|
||||||
"links": [],
|
"links": [],
|
||||||
"modified": "2023-01-18 15:48:58.114923",
|
"modified": "2023-02-28 15:43:04.470104",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Stock",
|
"module": "Stock",
|
||||||
"name": "Purchase Receipt Item",
|
"name": "Purchase Receipt Item",
|
||||||
|
|||||||
@@ -397,6 +397,7 @@ class StockReconciliation(StockController):
|
|||||||
"voucher_type": self.doctype,
|
"voucher_type": self.doctype,
|
||||||
"voucher_no": self.name,
|
"voucher_no": self.name,
|
||||||
"voucher_detail_no": row.name,
|
"voucher_detail_no": row.name,
|
||||||
|
"actual_qty": 0,
|
||||||
"company": self.company,
|
"company": self.company,
|
||||||
"stock_uom": frappe.db.get_value("Item", row.item_code, "stock_uom"),
|
"stock_uom": frappe.db.get_value("Item", row.item_code, "stock_uom"),
|
||||||
"is_cancelled": 1 if self.docstatus == 2 else 0,
|
"is_cancelled": 1 if self.docstatus == 2 else 0,
|
||||||
@@ -423,6 +424,8 @@ class StockReconciliation(StockController):
|
|||||||
data.valuation_rate = flt(row.valuation_rate)
|
data.valuation_rate = flt(row.valuation_rate)
|
||||||
data.stock_value_difference = -1 * flt(row.amount_difference)
|
data.stock_value_difference = -1 * flt(row.amount_difference)
|
||||||
|
|
||||||
|
self.update_inventory_dimensions(row, data)
|
||||||
|
|
||||||
return data
|
return data
|
||||||
|
|
||||||
def make_sle_on_cancel(self):
|
def make_sle_on_cancel(self):
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import frappe
|
|||||||
from frappe import _, throw
|
from frappe import _, throw
|
||||||
from frappe.model import child_table_fields, default_fields
|
from frappe.model import child_table_fields, default_fields
|
||||||
from frappe.model.meta import get_field_precision
|
from frappe.model.meta import get_field_precision
|
||||||
|
from frappe.query_builder.functions import CombineDatetime, IfNull, Sum
|
||||||
from frappe.utils import add_days, add_months, cint, cstr, flt, getdate
|
from frappe.utils import add_days, add_months, cint, cstr, flt, getdate
|
||||||
|
|
||||||
from erpnext import get_company_currency
|
from erpnext import get_company_currency
|
||||||
@@ -526,12 +527,8 @@ def get_barcode_data(items_list):
|
|||||||
|
|
||||||
itemwise_barcode = {}
|
itemwise_barcode = {}
|
||||||
for item in items_list:
|
for item in items_list:
|
||||||
barcodes = frappe.db.sql(
|
barcodes = frappe.db.get_all(
|
||||||
"""
|
"Item Barcode", filters={"parent": item.item_code}, fields="barcode"
|
||||||
select barcode from `tabItem Barcode` where parent = %s
|
|
||||||
""",
|
|
||||||
item.item_code,
|
|
||||||
as_dict=1,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
for barcode in barcodes:
|
for barcode in barcodes:
|
||||||
@@ -891,34 +888,36 @@ def get_item_price(args, item_code, ignore_party=False):
|
|||||||
:param item_code: str, Item Doctype field item_code
|
:param item_code: str, Item Doctype field item_code
|
||||||
"""
|
"""
|
||||||
|
|
||||||
args["item_code"] = item_code
|
ip = frappe.qb.DocType("Item Price")
|
||||||
|
query = (
|
||||||
conditions = """where item_code=%(item_code)s
|
frappe.qb.from_(ip)
|
||||||
and price_list=%(price_list)s
|
.select(ip.name, ip.price_list_rate, ip.uom)
|
||||||
and ifnull(uom, '') in ('', %(uom)s)"""
|
.where(
|
||||||
|
(ip.item_code == item_code)
|
||||||
conditions += "and ifnull(batch_no, '') in ('', %(batch_no)s)"
|
& (ip.price_list == args.get("price_list"))
|
||||||
|
& (IfNull(ip.uom, "").isin(["", args.get("uom")]))
|
||||||
|
& (IfNull(ip.batch_no, "").isin(["", args.get("batch_no")]))
|
||||||
|
)
|
||||||
|
.orderby(ip.valid_from, order=frappe.qb.desc)
|
||||||
|
.orderby(IfNull(ip.batch_no, ""), order=frappe.qb.desc)
|
||||||
|
.orderby(ip.uom, order=frappe.qb.desc)
|
||||||
|
)
|
||||||
|
|
||||||
if not ignore_party:
|
if not ignore_party:
|
||||||
if args.get("customer"):
|
if args.get("customer"):
|
||||||
conditions += " and customer=%(customer)s"
|
query = query.where(ip.customer == args.get("customer"))
|
||||||
elif args.get("supplier"):
|
elif args.get("supplier"):
|
||||||
conditions += " and supplier=%(supplier)s"
|
query = query.where(ip.supplier == args.get("supplier"))
|
||||||
else:
|
else:
|
||||||
conditions += "and (customer is null or customer = '') and (supplier is null or supplier = '')"
|
query = query.where((IfNull(ip.customer, "") == "") & (IfNull(ip.supplier, "") == ""))
|
||||||
|
|
||||||
if args.get("transaction_date"):
|
if args.get("transaction_date"):
|
||||||
conditions += """ and %(transaction_date)s between
|
query = query.where(
|
||||||
ifnull(valid_from, '2000-01-01') and ifnull(valid_upto, '2500-12-31')"""
|
(IfNull(ip.valid_from, "2000-01-01") <= args["transaction_date"])
|
||||||
|
& (IfNull(ip.valid_upto, "2500-12-31") >= args["transaction_date"])
|
||||||
|
)
|
||||||
|
|
||||||
return frappe.db.sql(
|
return query.run()
|
||||||
""" select name, price_list_rate, uom
|
|
||||||
from `tabItem Price` {conditions}
|
|
||||||
order by valid_from desc, ifnull(batch_no, '') desc, uom desc """.format(
|
|
||||||
conditions=conditions
|
|
||||||
),
|
|
||||||
args,
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def get_price_list_rate_for(args, item_code):
|
def get_price_list_rate_for(args, item_code):
|
||||||
@@ -1091,91 +1090,68 @@ def get_pos_profile(company, pos_profile=None, user=None):
|
|||||||
if not user:
|
if not user:
|
||||||
user = frappe.session["user"]
|
user = frappe.session["user"]
|
||||||
|
|
||||||
condition = "pfu.user = %(user)s AND pfu.default=1"
|
pf = frappe.qb.DocType("POS Profile")
|
||||||
if user and company:
|
pfu = frappe.qb.DocType("POS Profile User")
|
||||||
condition = "pfu.user = %(user)s AND pf.company = %(company)s AND pfu.default=1"
|
|
||||||
|
|
||||||
pos_profile = frappe.db.sql(
|
query = (
|
||||||
"""SELECT pf.*
|
frappe.qb.from_(pf)
|
||||||
FROM
|
.left_join(pfu)
|
||||||
`tabPOS Profile` pf LEFT JOIN `tabPOS Profile User` pfu
|
.on(pf.name == pfu.parent)
|
||||||
ON
|
.select(pf.star)
|
||||||
pf.name = pfu.parent
|
.where((pfu.user == user) & (pfu.default == 1))
|
||||||
WHERE
|
|
||||||
{cond} AND pf.disabled = 0
|
|
||||||
""".format(
|
|
||||||
cond=condition
|
|
||||||
),
|
|
||||||
{"user": user, "company": company},
|
|
||||||
as_dict=1,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if company:
|
||||||
|
query = query.where(pf.company == company)
|
||||||
|
|
||||||
|
pos_profile = query.run(as_dict=True)
|
||||||
|
|
||||||
if not pos_profile and company:
|
if not pos_profile and company:
|
||||||
pos_profile = frappe.db.sql(
|
pos_profile = (
|
||||||
"""SELECT pf.*
|
frappe.qb.from_(pf)
|
||||||
FROM
|
.left_join(pfu)
|
||||||
`tabPOS Profile` pf LEFT JOIN `tabPOS Profile User` pfu
|
.on(pf.name == pfu.parent)
|
||||||
ON
|
.select(pf.star)
|
||||||
pf.name = pfu.parent
|
.where((pf.company == company) & (pf.disabled == 0))
|
||||||
WHERE
|
).run(as_dict=True)
|
||||||
pf.company = %(company)s AND pf.disabled = 0
|
|
||||||
""",
|
|
||||||
{"company": company},
|
|
||||||
as_dict=1,
|
|
||||||
)
|
|
||||||
|
|
||||||
return pos_profile and pos_profile[0] or None
|
return pos_profile and pos_profile[0] or None
|
||||||
|
|
||||||
|
|
||||||
def get_serial_nos_by_fifo(args, sales_order=None):
|
def get_serial_nos_by_fifo(args, sales_order=None):
|
||||||
if frappe.db.get_single_value("Stock Settings", "automatically_set_serial_nos_based_on_fifo"):
|
if frappe.db.get_single_value("Stock Settings", "automatically_set_serial_nos_based_on_fifo"):
|
||||||
return "\n".join(
|
sn = frappe.qb.DocType("Serial No")
|
||||||
frappe.db.sql_list(
|
query = (
|
||||||
"""select name from `tabSerial No`
|
frappe.qb.from_(sn)
|
||||||
where item_code=%(item_code)s and warehouse=%(warehouse)s and
|
.select(sn.name)
|
||||||
sales_order=IF(%(sales_order)s IS NULL, sales_order, %(sales_order)s)
|
.where((sn.item_code == args.item_code) & (sn.warehouse == args.warehouse))
|
||||||
order by timestamp(purchase_date, purchase_time)
|
.orderby(CombineDatetime(sn.purchase_date, sn.purchase_time))
|
||||||
asc limit %(qty)s""",
|
.limit(abs(cint(args.stock_qty)))
|
||||||
{
|
|
||||||
"item_code": args.item_code,
|
|
||||||
"warehouse": args.warehouse,
|
|
||||||
"qty": abs(cint(args.stock_qty)),
|
|
||||||
"sales_order": sales_order,
|
|
||||||
},
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if sales_order:
|
||||||
|
query = query.where(sn.sales_order == sales_order)
|
||||||
|
if args.batch_no:
|
||||||
|
query = query.where(sn.batch_no == args.batch_no)
|
||||||
|
|
||||||
def get_serial_no_batchwise(args, sales_order=None):
|
serial_nos = query.run(as_list=True)
|
||||||
if frappe.db.get_single_value("Stock Settings", "automatically_set_serial_nos_based_on_fifo"):
|
serial_nos = [s[0] for s in serial_nos]
|
||||||
return "\n".join(
|
|
||||||
frappe.db.sql_list(
|
return "\n".join(serial_nos)
|
||||||
"""select name from `tabSerial No`
|
|
||||||
where item_code=%(item_code)s and warehouse=%(warehouse)s and
|
|
||||||
sales_order=IF(%(sales_order)s IS NULL, sales_order, %(sales_order)s)
|
|
||||||
and batch_no=IF(%(batch_no)s IS NULL, batch_no, %(batch_no)s) order
|
|
||||||
by timestamp(purchase_date, purchase_time) asc limit %(qty)s""",
|
|
||||||
{
|
|
||||||
"item_code": args.item_code,
|
|
||||||
"warehouse": args.warehouse,
|
|
||||||
"batch_no": args.batch_no,
|
|
||||||
"qty": abs(cint(args.stock_qty)),
|
|
||||||
"sales_order": sales_order,
|
|
||||||
},
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
@frappe.whitelist()
|
@frappe.whitelist()
|
||||||
def get_conversion_factor(item_code, uom):
|
def get_conversion_factor(item_code, uom):
|
||||||
variant_of = frappe.db.get_value("Item", item_code, "variant_of", cache=True)
|
variant_of = frappe.db.get_value("Item", item_code, "variant_of", cache=True)
|
||||||
filters = {"parent": item_code, "uom": uom}
|
filters = {"parent": item_code, "uom": uom}
|
||||||
|
|
||||||
if variant_of:
|
if variant_of:
|
||||||
filters["parent"] = ("in", (item_code, variant_of))
|
filters["parent"] = ("in", (item_code, variant_of))
|
||||||
conversion_factor = frappe.db.get_value("UOM Conversion Detail", filters, "conversion_factor")
|
conversion_factor = frappe.db.get_value("UOM Conversion Detail", filters, "conversion_factor")
|
||||||
if not conversion_factor:
|
if not conversion_factor:
|
||||||
stock_uom = frappe.db.get_value("Item", item_code, "stock_uom")
|
stock_uom = frappe.db.get_value("Item", item_code, "stock_uom")
|
||||||
conversion_factor = get_uom_conv_factor(uom, stock_uom)
|
conversion_factor = get_uom_conv_factor(uom, stock_uom)
|
||||||
|
|
||||||
return {"conversion_factor": conversion_factor or 1.0}
|
return {"conversion_factor": conversion_factor or 1.0}
|
||||||
|
|
||||||
|
|
||||||
@@ -1217,12 +1193,16 @@ def get_bin_details(item_code, warehouse, company=None, include_child_warehouses
|
|||||||
|
|
||||||
|
|
||||||
def get_company_total_stock(item_code, company):
|
def get_company_total_stock(item_code, company):
|
||||||
return frappe.db.sql(
|
bin = frappe.qb.DocType("Bin")
|
||||||
"""SELECT sum(actual_qty) from
|
wh = frappe.qb.DocType("Warehouse")
|
||||||
(`tabBin` INNER JOIN `tabWarehouse` ON `tabBin`.warehouse = `tabWarehouse`.name)
|
|
||||||
WHERE `tabWarehouse`.company = %s and `tabBin`.item_code = %s""",
|
return (
|
||||||
(company, item_code),
|
frappe.qb.from_(bin)
|
||||||
)[0][0]
|
.inner_join(wh)
|
||||||
|
.on(bin.warehouse == wh.name)
|
||||||
|
.select(Sum(bin.actual_qty))
|
||||||
|
.where((wh.company == company) & (bin.item_code == item_code))
|
||||||
|
).run()[0][0]
|
||||||
|
|
||||||
|
|
||||||
@frappe.whitelist()
|
@frappe.whitelist()
|
||||||
@@ -1231,6 +1211,7 @@ def get_serial_no_details(item_code, warehouse, stock_qty, serial_no):
|
|||||||
{"item_code": item_code, "warehouse": warehouse, "stock_qty": stock_qty, "serial_no": serial_no}
|
{"item_code": item_code, "warehouse": warehouse, "stock_qty": stock_qty, "serial_no": serial_no}
|
||||||
)
|
)
|
||||||
serial_no = get_serial_no(args)
|
serial_no = get_serial_no(args)
|
||||||
|
|
||||||
return {"serial_no": serial_no}
|
return {"serial_no": serial_no}
|
||||||
|
|
||||||
|
|
||||||
@@ -1250,6 +1231,7 @@ def get_bin_details_and_serial_nos(
|
|||||||
bin_details_and_serial_nos.update(
|
bin_details_and_serial_nos.update(
|
||||||
get_serial_no_details(item_code, warehouse, stock_qty, serial_no)
|
get_serial_no_details(item_code, warehouse, stock_qty, serial_no)
|
||||||
)
|
)
|
||||||
|
|
||||||
return bin_details_and_serial_nos
|
return bin_details_and_serial_nos
|
||||||
|
|
||||||
|
|
||||||
@@ -1264,6 +1246,7 @@ def get_batch_qty_and_serial_no(batch_no, stock_qty, warehouse, item_code, has_s
|
|||||||
)
|
)
|
||||||
serial_no = get_serial_no(args)
|
serial_no = get_serial_no(args)
|
||||||
batch_qty_and_serial_no.update({"serial_no": serial_no})
|
batch_qty_and_serial_no.update({"serial_no": serial_no})
|
||||||
|
|
||||||
return batch_qty_and_serial_no
|
return batch_qty_and_serial_no
|
||||||
|
|
||||||
|
|
||||||
@@ -1336,7 +1319,6 @@ def apply_price_list(args, as_doc=False):
|
|||||||
def apply_price_list_on_item(args):
|
def apply_price_list_on_item(args):
|
||||||
item_doc = frappe.db.get_value("Item", args.item_code, ["name", "variant_of"], as_dict=1)
|
item_doc = frappe.db.get_value("Item", args.item_code, ["name", "variant_of"], as_dict=1)
|
||||||
item_details = get_price_list_rate(args, item_doc)
|
item_details = get_price_list_rate(args, item_doc)
|
||||||
|
|
||||||
item_details.update(get_pricing_rule_for_item(args))
|
item_details.update(get_pricing_rule_for_item(args))
|
||||||
|
|
||||||
return item_details
|
return item_details
|
||||||
@@ -1420,12 +1402,12 @@ def get_valuation_rate(item_code, company, warehouse=None):
|
|||||||
) or {"valuation_rate": 0}
|
) or {"valuation_rate": 0}
|
||||||
|
|
||||||
elif not item.get("is_stock_item"):
|
elif not item.get("is_stock_item"):
|
||||||
valuation_rate = frappe.db.sql(
|
pi_item = frappe.qb.DocType("Purchase Invoice Item")
|
||||||
"""select sum(base_net_amount) / sum(qty*conversion_factor)
|
valuation_rate = (
|
||||||
from `tabPurchase Invoice Item`
|
frappe.qb.from_(pi_item)
|
||||||
where item_code = %s and docstatus=1""",
|
.select((Sum(pi_item.base_net_amount) / Sum(pi_item.qty * pi_item.conversion_factor)))
|
||||||
item_code,
|
.where((pi_item.docstatus == 1) & (pi_item.item_code == item_code))
|
||||||
)
|
).run()
|
||||||
|
|
||||||
if valuation_rate:
|
if valuation_rate:
|
||||||
return {"valuation_rate": valuation_rate[0][0] or 0.0}
|
return {"valuation_rate": valuation_rate[0][0] or 0.0}
|
||||||
@@ -1451,7 +1433,7 @@ def get_serial_no(args, serial_nos=None, sales_order=None):
|
|||||||
if args.get("warehouse") and args.get("stock_qty") and args.get("item_code"):
|
if args.get("warehouse") and args.get("stock_qty") and args.get("item_code"):
|
||||||
has_serial_no = frappe.get_value("Item", {"item_code": args.item_code}, "has_serial_no")
|
has_serial_no = frappe.get_value("Item", {"item_code": args.item_code}, "has_serial_no")
|
||||||
if args.get("batch_no") and has_serial_no == 1:
|
if args.get("batch_no") and has_serial_no == 1:
|
||||||
return get_serial_no_batchwise(args, sales_order)
|
return get_serial_nos_by_fifo(args, sales_order)
|
||||||
elif has_serial_no == 1:
|
elif has_serial_no == 1:
|
||||||
args = json.dumps(
|
args = json.dumps(
|
||||||
{
|
{
|
||||||
@@ -1483,31 +1465,35 @@ def get_blanket_order_details(args):
|
|||||||
args = frappe._dict(json.loads(args))
|
args = frappe._dict(json.loads(args))
|
||||||
|
|
||||||
blanket_order_details = None
|
blanket_order_details = None
|
||||||
condition = ""
|
|
||||||
if args.item_code:
|
|
||||||
if args.customer and args.doctype == "Sales Order":
|
|
||||||
condition = " and bo.customer=%(customer)s"
|
|
||||||
elif args.supplier and args.doctype == "Purchase Order":
|
|
||||||
condition = " and bo.supplier=%(supplier)s"
|
|
||||||
if args.blanket_order:
|
|
||||||
condition += " and bo.name =%(blanket_order)s"
|
|
||||||
if args.transaction_date:
|
|
||||||
condition += " and bo.to_date>=%(transaction_date)s"
|
|
||||||
|
|
||||||
blanket_order_details = frappe.db.sql(
|
if args.item_code:
|
||||||
"""
|
bo = frappe.qb.DocType("Blanket Order")
|
||||||
select boi.rate as blanket_order_rate, bo.name as blanket_order
|
bo_item = frappe.qb.DocType("Blanket Order Item")
|
||||||
from `tabBlanket Order` bo, `tabBlanket Order Item` boi
|
|
||||||
where bo.company=%(company)s and boi.item_code=%(item_code)s
|
query = (
|
||||||
and bo.docstatus=1 and bo.name = boi.parent {0}
|
frappe.qb.from_(bo)
|
||||||
""".format(
|
.from_(bo_item)
|
||||||
condition
|
.select(bo_item.rate.as_("blanket_order_rate"), bo.name.as_("blanket_order"))
|
||||||
),
|
.where(
|
||||||
args,
|
(bo.company == args.company)
|
||||||
as_dict=True,
|
& (bo_item.item_code == args.item_code)
|
||||||
|
& (bo.docstatus == 1)
|
||||||
|
& (bo.name == bo_item.parent)
|
||||||
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if args.customer and args.doctype == "Sales Order":
|
||||||
|
query = query.where(bo.customer == args.customer)
|
||||||
|
elif args.supplier and args.doctype == "Purchase Order":
|
||||||
|
query = query.where(bo.supplier == args.supplier)
|
||||||
|
if args.blanket_order:
|
||||||
|
query = query.where(bo.name == args.blanket_order)
|
||||||
|
if args.transaction_date:
|
||||||
|
query = query.where(bo.to_date >= args.transaction_date)
|
||||||
|
|
||||||
|
blanket_order_details = query.run(as_dict=True)
|
||||||
blanket_order_details = blanket_order_details[0] if blanket_order_details else ""
|
blanket_order_details = blanket_order_details[0] if blanket_order_details else ""
|
||||||
|
|
||||||
return blanket_order_details
|
return blanket_order_details
|
||||||
|
|
||||||
|
|
||||||
@@ -1517,10 +1503,10 @@ def get_so_reservation_for_item(args):
|
|||||||
if get_reserved_qty_for_so(args.get("against_sales_order"), args.get("item_code")):
|
if get_reserved_qty_for_so(args.get("against_sales_order"), args.get("item_code")):
|
||||||
reserved_so = args.get("against_sales_order")
|
reserved_so = args.get("against_sales_order")
|
||||||
elif args.get("against_sales_invoice"):
|
elif args.get("against_sales_invoice"):
|
||||||
sales_order = frappe.db.sql(
|
sales_order = frappe.db.get_all(
|
||||||
"""select sales_order from `tabSales Invoice Item` where
|
"Sales Invoice Item",
|
||||||
parent=%s and item_code=%s""",
|
filters={"parent": args.get("against_sales_invoice"), "item_code": args.get("item_code")},
|
||||||
(args.get("against_sales_invoice"), args.get("item_code")),
|
fields="sales_order",
|
||||||
)
|
)
|
||||||
if sales_order and sales_order[0]:
|
if sales_order and sales_order[0]:
|
||||||
if get_reserved_qty_for_so(sales_order[0][0], args.get("item_code")):
|
if get_reserved_qty_for_so(sales_order[0][0], args.get("item_code")):
|
||||||
@@ -1532,13 +1518,14 @@ def get_so_reservation_for_item(args):
|
|||||||
|
|
||||||
|
|
||||||
def get_reserved_qty_for_so(sales_order, item_code):
|
def get_reserved_qty_for_so(sales_order, item_code):
|
||||||
reserved_qty = frappe.db.sql(
|
reserved_qty = frappe.db.get_value(
|
||||||
"""select sum(qty) from `tabSales Order Item`
|
"Sales Order Item",
|
||||||
where parent=%s and item_code=%s and ensure_delivery_based_on_produced_serial_no=1
|
filters={
|
||||||
""",
|
"parent": sales_order,
|
||||||
(sales_order, item_code),
|
"item_code": item_code,
|
||||||
|
"ensure_delivery_based_on_produced_serial_no": 1,
|
||||||
|
},
|
||||||
|
fieldname="sum(qty)",
|
||||||
)
|
)
|
||||||
if reserved_qty and reserved_qty[0][0]:
|
|
||||||
return reserved_qty[0][0]
|
return reserved_qty or 0
|
||||||
else:
|
|
||||||
return 0
|
|
||||||
|
|||||||
@@ -9916,3 +9916,5 @@ Cost and Freight,Kosten und Fracht,
|
|||||||
Delivered at Place,Geliefert benannter Ort,
|
Delivered at Place,Geliefert benannter Ort,
|
||||||
Delivered at Place Unloaded,Geliefert benannter Ort entladen,
|
Delivered at Place Unloaded,Geliefert benannter Ort entladen,
|
||||||
Delivered Duty Paid,Geliefert verzollt,
|
Delivered Duty Paid,Geliefert verzollt,
|
||||||
|
Discount Validity,Frist für den Rabatt,
|
||||||
|
Discount Validity Based On,Frist für den Rabatt berechnet sich nach,
|
||||||
|
|||||||
|
Can't render this file because it is too large.
|
Reference in New Issue
Block a user