Merge branch 'develop' into refactor/stock/report/incorrect-stock-value
This commit is contained in:
commit
afb323b01c
@ -14,6 +14,7 @@ from erpnext.accounts.utils import (
|
|||||||
QueryPaymentLedger,
|
QueryPaymentLedger,
|
||||||
get_outstanding_invoices,
|
get_outstanding_invoices,
|
||||||
reconcile_against_document,
|
reconcile_against_document,
|
||||||
|
update_reference_in_payment_entry,
|
||||||
)
|
)
|
||||||
from erpnext.controllers.accounts_controller import get_advance_payment_entries
|
from erpnext.controllers.accounts_controller import get_advance_payment_entries
|
||||||
|
|
||||||
@ -212,6 +213,23 @@ class PaymentReconciliation(Document):
|
|||||||
inv.currency = entry.get("currency")
|
inv.currency = entry.get("currency")
|
||||||
inv.outstanding_amount = flt(entry.get("outstanding_amount"))
|
inv.outstanding_amount = flt(entry.get("outstanding_amount"))
|
||||||
|
|
||||||
|
def get_difference_amount(self, allocated_entry):
|
||||||
|
if allocated_entry.get("reference_type") != "Payment Entry":
|
||||||
|
return
|
||||||
|
|
||||||
|
dr_or_cr = (
|
||||||
|
"credit_in_account_currency"
|
||||||
|
if erpnext.get_party_account_type(self.party_type) == "Receivable"
|
||||||
|
else "debit_in_account_currency"
|
||||||
|
)
|
||||||
|
|
||||||
|
row = self.get_payment_details(allocated_entry, dr_or_cr)
|
||||||
|
|
||||||
|
doc = frappe.get_doc(allocated_entry.reference_type, allocated_entry.reference_name)
|
||||||
|
update_reference_in_payment_entry(row, doc, do_not_save=True)
|
||||||
|
|
||||||
|
return doc.difference_amount
|
||||||
|
|
||||||
@frappe.whitelist()
|
@frappe.whitelist()
|
||||||
def allocate_entries(self, args):
|
def allocate_entries(self, args):
|
||||||
self.validate_entries()
|
self.validate_entries()
|
||||||
@ -227,12 +245,16 @@ class PaymentReconciliation(Document):
|
|||||||
res = self.get_allocated_entry(pay, inv, pay["amount"])
|
res = self.get_allocated_entry(pay, inv, pay["amount"])
|
||||||
inv["outstanding_amount"] = flt(inv.get("outstanding_amount")) - flt(pay.get("amount"))
|
inv["outstanding_amount"] = flt(inv.get("outstanding_amount")) - flt(pay.get("amount"))
|
||||||
pay["amount"] = 0
|
pay["amount"] = 0
|
||||||
|
|
||||||
|
res.difference_amount = self.get_difference_amount(res)
|
||||||
|
|
||||||
if pay.get("amount") == 0:
|
if pay.get("amount") == 0:
|
||||||
entries.append(res)
|
entries.append(res)
|
||||||
break
|
break
|
||||||
elif inv.get("outstanding_amount") == 0:
|
elif inv.get("outstanding_amount") == 0:
|
||||||
entries.append(res)
|
entries.append(res)
|
||||||
continue
|
continue
|
||||||
|
|
||||||
else:
|
else:
|
||||||
break
|
break
|
||||||
|
|
||||||
|
|||||||
@ -155,7 +155,6 @@ def adjust_account(data, period_list, consolidated=False):
|
|||||||
for d in data:
|
for d in data:
|
||||||
for period in period_list:
|
for period in period_list:
|
||||||
key = period if consolidated else period.key
|
key = period if consolidated else period.key
|
||||||
d[key] = totals[d["account"]]
|
|
||||||
d["total"] = totals[d["account"]]
|
d["total"] = totals[d["account"]]
|
||||||
return data
|
return data
|
||||||
|
|
||||||
|
|||||||
@ -44,7 +44,7 @@ frappe.query_reports["Opportunity Summary by Sales Stage"] = {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
fieldname: "opportunity_source",
|
fieldname: "opportunity_source",
|
||||||
label: __("Oppoturnity Source"),
|
label: __("Opportunity Source"),
|
||||||
fieldtype: "Link",
|
fieldtype: "Link",
|
||||||
options: "Lead Source",
|
options: "Lead Source",
|
||||||
},
|
},
|
||||||
@ -62,4 +62,4 @@ frappe.query_reports["Opportunity Summary by Sales Stage"] = {
|
|||||||
default: frappe.defaults.get_user_default("Company")
|
default: frappe.defaults.get_user_default("Company")
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
};
|
};
|
||||||
|
|||||||
@ -85,8 +85,8 @@ def get_chart_data(job_card_details, filters):
|
|||||||
open_job_cards.append(periodic_data.get("Open").get(d))
|
open_job_cards.append(periodic_data.get("Open").get(d))
|
||||||
completed.append(periodic_data.get("Completed").get(d))
|
completed.append(periodic_data.get("Completed").get(d))
|
||||||
|
|
||||||
datasets.append({"name": "Open", "values": open_job_cards})
|
datasets.append({"name": _("Open"), "values": open_job_cards})
|
||||||
datasets.append({"name": "Completed", "values": completed})
|
datasets.append({"name": _("Completed"), "values": completed})
|
||||||
|
|
||||||
chart = {"data": {"labels": labels, "datasets": datasets}, "type": "bar"}
|
chart = {"data": {"labels": labels, "datasets": datasets}, "type": "bar"}
|
||||||
|
|
||||||
|
|||||||
@ -83,6 +83,7 @@ def get_chart_based_on_status(data):
|
|||||||
for d in data:
|
for d in data:
|
||||||
status_wise_data[d.status] += 1
|
status_wise_data[d.status] += 1
|
||||||
|
|
||||||
|
labels = [_(label) for label in labels]
|
||||||
values = [status_wise_data[label] for label in labels]
|
values = [status_wise_data[label] for label in labels]
|
||||||
|
|
||||||
chart = {
|
chart = {
|
||||||
@ -95,7 +96,7 @@ def get_chart_based_on_status(data):
|
|||||||
|
|
||||||
|
|
||||||
def get_chart_based_on_age(data):
|
def get_chart_based_on_age(data):
|
||||||
labels = ["0-30 Days", "30-60 Days", "60-90 Days", "90 Above"]
|
labels = [_("0-30 Days"), _("30-60 Days"), _("60-90 Days"), _("90 Above")]
|
||||||
|
|
||||||
age_wise_data = {"0-30 Days": 0, "30-60 Days": 0, "60-90 Days": 0, "90 Above": 0}
|
age_wise_data = {"0-30 Days": 0, "30-60 Days": 0, "60-90 Days": 0, "90 Above": 0}
|
||||||
|
|
||||||
@ -135,8 +136,8 @@ def get_chart_based_on_qty(data, filters):
|
|||||||
pending.append(periodic_data.get("Pending").get(d))
|
pending.append(periodic_data.get("Pending").get(d))
|
||||||
completed.append(periodic_data.get("Completed").get(d))
|
completed.append(periodic_data.get("Completed").get(d))
|
||||||
|
|
||||||
datasets.append({"name": "Pending", "values": pending})
|
datasets.append({"name": _("Pending"), "values": pending})
|
||||||
datasets.append({"name": "Completed", "values": completed})
|
datasets.append({"name": _("Completed"), "values": completed})
|
||||||
|
|
||||||
chart = {
|
chart = {
|
||||||
"data": {"labels": labels, "datasets": datasets},
|
"data": {"labels": labels, "datasets": datasets},
|
||||||
|
|||||||
@ -91,9 +91,9 @@ def get_chart_data(data):
|
|||||||
"data": {
|
"data": {
|
||||||
"labels": labels[:30],
|
"labels": labels[:30],
|
||||||
"datasets": [
|
"datasets": [
|
||||||
{"name": "Overdue", "values": overdue[:30]},
|
{"name": _("Overdue"), "values": overdue[:30]},
|
||||||
{"name": "Completed", "values": completed[:30]},
|
{"name": _("Completed"), "values": completed[:30]},
|
||||||
{"name": "Total Tasks", "values": total[:30]},
|
{"name": _("Total Tasks"), "values": total[:30]},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
"type": "bar",
|
"type": "bar",
|
||||||
|
|||||||
@ -671,7 +671,7 @@ frappe.help.help_links["List/Item"] = [
|
|||||||
label: "Item Valuation",
|
label: "Item Valuation",
|
||||||
url:
|
url:
|
||||||
docsUrl +
|
docsUrl +
|
||||||
"user/manual/en/stock/articles/item-valuation-fifo-and-moving-average",
|
"user/manual/en/stock/articles/calculation-of-valuation-rate-in-fifo-and-moving-average",
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|||||||
@ -21,6 +21,11 @@ erpnext.utils.BarcodeScanner = class BarcodeScanner {
|
|||||||
this.items_table_name = opts.items_table_name || "items";
|
this.items_table_name = opts.items_table_name || "items";
|
||||||
this.items_table = this.frm.doc[this.items_table_name];
|
this.items_table = this.frm.doc[this.items_table_name];
|
||||||
|
|
||||||
|
// optional sound name to play when scan either fails or passes.
|
||||||
|
// see https://frappeframework.com/docs/v14/user/en/python-api/hooks#sounds
|
||||||
|
this.success_sound = opts.play_success_sound;
|
||||||
|
this.fail_sound = opts.play_fail_sound;
|
||||||
|
|
||||||
// any API that takes `search_value` as input and returns dictionary as follows
|
// any API that takes `search_value` as input and returns dictionary as follows
|
||||||
// {
|
// {
|
||||||
// item_code: "HORSESHOE", // present if any item was found
|
// item_code: "HORSESHOE", // present if any item was found
|
||||||
@ -54,19 +59,24 @@ erpnext.utils.BarcodeScanner = class BarcodeScanner {
|
|||||||
if (!data || Object.keys(data).length === 0) {
|
if (!data || Object.keys(data).length === 0) {
|
||||||
this.show_alert(__("Cannot find Item with this Barcode"), "red");
|
this.show_alert(__("Cannot find Item with this Barcode"), "red");
|
||||||
this.clean_up();
|
this.clean_up();
|
||||||
|
this.play_fail_sound();
|
||||||
reject();
|
reject();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
me.update_table(data).then(row => {
|
me.update_table(data).then(row => {
|
||||||
row ? resolve(row) : reject();
|
this.play_success_sound();
|
||||||
|
resolve(row);
|
||||||
|
}).catch(() => {
|
||||||
|
this.play_fail_sound();
|
||||||
|
reject();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
update_table(data) {
|
update_table(data) {
|
||||||
return new Promise(resolve => {
|
return new Promise((resolve, reject) => {
|
||||||
let cur_grid = this.frm.fields_dict[this.items_table_name].grid;
|
let cur_grid = this.frm.fields_dict[this.items_table_name].grid;
|
||||||
|
|
||||||
const {item_code, barcode, batch_no, serial_no, uom} = data;
|
const {item_code, barcode, batch_no, serial_no, uom} = data;
|
||||||
@ -77,6 +87,7 @@ erpnext.utils.BarcodeScanner = class BarcodeScanner {
|
|||||||
if (this.dont_allow_new_row) {
|
if (this.dont_allow_new_row) {
|
||||||
this.show_alert(__("Maximum quantity scanned for item {0}.", [item_code]), "red");
|
this.show_alert(__("Maximum quantity scanned for item {0}.", [item_code]), "red");
|
||||||
this.clean_up();
|
this.clean_up();
|
||||||
|
reject();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -88,6 +99,7 @@ erpnext.utils.BarcodeScanner = class BarcodeScanner {
|
|||||||
|
|
||||||
if (this.is_duplicate_serial_no(row, serial_no)) {
|
if (this.is_duplicate_serial_no(row, serial_no)) {
|
||||||
this.clean_up();
|
this.clean_up();
|
||||||
|
reject();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -219,6 +231,14 @@ erpnext.utils.BarcodeScanner = class BarcodeScanner {
|
|||||||
return this.items_table.find((d) => !d.item_code);
|
return this.items_table.find((d) => !d.item_code);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
play_success_sound() {
|
||||||
|
this.success_sound && frappe.utils.play_sound(this.success_sound);
|
||||||
|
}
|
||||||
|
|
||||||
|
play_fail_sound() {
|
||||||
|
this.fail_sound && frappe.utils.play_sound(this.fail_sound);
|
||||||
|
}
|
||||||
|
|
||||||
clean_up() {
|
clean_up() {
|
||||||
this.scan_barcode_field.set_value("");
|
this.scan_barcode_field.set_value("");
|
||||||
refresh_field(this.items_table_name);
|
refresh_field(this.items_table_name);
|
||||||
|
|||||||
@ -62,22 +62,28 @@ def get_data(filters, columns):
|
|||||||
|
|
||||||
|
|
||||||
def get_item_price_qty_data(filters):
|
def get_item_price_qty_data(filters):
|
||||||
conditions = ""
|
item_price = frappe.qb.DocType("Item Price")
|
||||||
if filters.get("item_code"):
|
bin = frappe.qb.DocType("Bin")
|
||||||
conditions += "where a.item_code=%(item_code)s"
|
|
||||||
|
|
||||||
item_results = frappe.db.sql(
|
query = (
|
||||||
"""select a.item_code, a.item_name, a.name as price_list_name,
|
frappe.qb.from_(item_price)
|
||||||
a.brand as brand, b.warehouse as warehouse, b.actual_qty as actual_qty
|
.left_join(bin)
|
||||||
from `tabItem Price` a left join `tabBin` b
|
.on(item_price.item_code == bin.item_code)
|
||||||
ON a.item_code = b.item_code
|
.select(
|
||||||
{conditions}""".format(
|
item_price.item_code,
|
||||||
conditions=conditions
|
item_price.item_name,
|
||||||
),
|
item_price.name.as_("price_list_name"),
|
||||||
filters,
|
item_price.brand.as_("brand"),
|
||||||
as_dict=1,
|
bin.warehouse.as_("warehouse"),
|
||||||
|
bin.actual_qty.as_("actual_qty"),
|
||||||
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if filters.get("item_code"):
|
||||||
|
query = query.where(item_price.item_code == filters.get("item_code"))
|
||||||
|
|
||||||
|
item_results = query.run(as_dict=True)
|
||||||
|
|
||||||
price_list_names = list(set(item.price_list_name for item in item_results))
|
price_list_names = list(set(item.price_list_name for item in item_results))
|
||||||
|
|
||||||
buying_price_map = get_price_map(price_list_names, buying=1)
|
buying_price_map = get_price_map(price_list_names, buying=1)
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user