fix(pos): multiple pos fixes and additions (#24227)

* fix: make custom fields in pos invoice similar to sales invoice

* feat: allow/disallow rate & discount change

* fix: any pos profile can be selected while creating pos opening

* fix: cannot add item to cart

* fix: validate phone payment only if payment request exists

* fix: replace pos payment method patch

* chore: rearrange item & customer group filter

* fix: allow/disallow invoice level discount

* fix: updating qty of item with uom having space char

* fix: move configuration checbox to config section

* fix: invalid item rate trigger

* fix: cannot remove item from draft invoices

* fix: customer currency not set in pos invoice

* fix: duplicate item error message

* fix: sales uom not fetched in pos invoice

* fix: cannot add taxes to pos invoice for uae region

* fix: cannot merge pos invoice into credit note

* fix: tax calculation while merging pos invoices

* feat: delete draft orders from order list

* fix: merging of pos invoice with pricing rules
This commit is contained in:
Saqib 2021-01-28 17:58:55 +05:30 committed by GitHub
parent 0d9a8ae4d2
commit ac9e6ff704
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
22 changed files with 194 additions and 65 deletions

View File

@ -165,9 +165,9 @@ def toggle_disabling(doc):
frappe.clear_cache(doctype=doctype)
def get_doctypes_with_dimensions():
doclist = ["GL Entry", "Sales Invoice", "Purchase Invoice", "Payment Entry", "Asset",
doclist = ["GL Entry", "Sales Invoice", "POS Invoice", "Purchase Invoice", "Payment Entry", "Asset",
"Expense Claim", "Expense Claim Detail", "Expense Taxes and Charges", "Stock Entry", "Budget", "Payroll Entry", "Delivery Note",
"Sales Invoice Item", "Purchase Invoice Item", "Purchase Order Item", "Journal Entry Account", "Material Request Item", "Delivery Note Item",
"Sales Invoice Item", "POS Invoice Item", "Purchase Invoice Item", "Purchase Order Item", "Journal Entry Account", "Material Request Item", "Delivery Note Item",
"Purchase Receipt Item", "Stock Entry Detail", "Payment Entry Deduction", "Sales Taxes and Charges", "Purchase Taxes and Charges", "Shipping Rule",
"Landed Cost Item", "Asset Value Adjustment", "Loyalty Program", "Fee Schedule", "Fee Structure", "Stock Reconciliation",
"Travel Request", "Fees", "POS Profile", "Opening Invoice Creation Tool", "Opening Invoice Creation Tool Item", "Subscription",

View File

@ -57,7 +57,11 @@ class POSClosingEntry(Document):
if not invalid_rows:
return
error_list = [_("Row #{}: {}").format(row.get('idx'), row.get('msg')) for row in invalid_rows]
error_list = []
for row in invalid_rows:
for msg in row.get('msg'):
error_list.append(_("Row #{}: {}").format(row.get('idx'), msg))
frappe.throw(error_list, title=_("Invalid POS Invoices"), as_list=True)
def on_submit(self):

View File

@ -2,6 +2,7 @@
// For license information, please see license.txt
{% include 'erpnext/selling/sales_common.js' %};
frappe.provide("erpnext.accounts");
erpnext.selling.POSInvoiceController = erpnext.selling.SellingController.extend({
setup(doc) {
@ -9,12 +10,18 @@ erpnext.selling.POSInvoiceController = erpnext.selling.SellingController.extend(
this._super(doc);
},
company: function() {
erpnext.accounts.dimensions.update_dimension(this.frm, this.frm.doctype);
},
onload(doc) {
this._super();
if(doc.__islocal && doc.is_pos && frappe.get_route_str() !== 'point-of-sale') {
this.frm.script_manager.trigger("is_pos");
this.frm.refresh_fields();
}
erpnext.accounts.dimensions.setup_dimension_filters(this.frm, this.frm.doctype);
},
refresh(doc) {

View File

@ -78,7 +78,7 @@ class POSInvoice(SalesInvoice):
mode_of_payment=pay.mode_of_payment, status="Paid"),
fieldname="grand_total")
if pay.amount != paid_amt:
if paid_amt and pay.amount != paid_amt:
return frappe.throw(_("Payment related to {0} is not completed").format(pay.mode_of_payment))
def validate_stock_availablility(self):
@ -297,7 +297,9 @@ class POSInvoice(SalesInvoice):
self.set(fieldname, profile.get(fieldname))
if self.customer:
customer_price_list, customer_group = frappe.db.get_value("Customer", self.customer, ['default_price_list', 'customer_group'])
customer_price_list, customer_group, customer_currency = frappe.db.get_value(
"Customer", self.customer, ['default_price_list', 'customer_group', 'default_currency']
)
customer_group_price_list = frappe.db.get_value("Customer Group", customer_group, 'default_price_list')
selling_price_list = customer_price_list or customer_group_price_list or profile.get('selling_price_list')
else:
@ -305,6 +307,8 @@ class POSInvoice(SalesInvoice):
if selling_price_list:
self.set('selling_price_list', selling_price_list)
if customer_currency != profile.get('currency'):
self.set('currency', customer_currency)
# set pos values in items
for item in self.get("items"):

View File

@ -5,10 +5,10 @@
from __future__ import unicode_literals
import frappe
from frappe import _
from frappe.utils import cint, flt, add_months, today, date_diff, getdate, add_days, cstr, nowdate
from frappe.model.document import Document
from frappe.model.mapper import map_doc
from frappe.model import default_fields
from frappe.model.document import Document
from frappe.model.mapper import map_doc, map_child_doc
from frappe.utils import flt, getdate, nowdate
from six import iteritems
@ -83,7 +83,7 @@ class POSInvoiceMergeLog(Document):
credit_note.is_consolidated = 1
# TODO: return could be against multiple sales invoice which could also have been consolidated?
credit_note.return_against = self.consolidated_invoice
# credit_note.return_against = self.consolidated_invoice
credit_note.save()
credit_note.submit()
self.consolidated_credit_note = credit_note.name
@ -111,7 +111,9 @@ class POSInvoiceMergeLog(Document):
i.qty = i.qty + item.qty
if not found:
item.rate = item.net_rate
items.append(item)
item.price_list_rate = 0
si_item = map_child_doc(item, invoice, {"doctype": "Sales Invoice Item"})
items.append(si_item)
for tax in doc.get('taxes'):
found = False
@ -147,6 +149,8 @@ class POSInvoiceMergeLog(Document):
invoice.set('taxes', taxes)
invoice.additional_discount_percentage = 0
invoice.discount_amount = 0.0
invoice.taxes_and_charges = None
invoice.ignore_pricing_rule = 1
return invoice

View File

@ -12,8 +12,6 @@
"company",
"country",
"column_break_9",
"update_stock",
"ignore_pricing_rule",
"warehouse",
"campaign",
"company_address",
@ -25,8 +23,14 @@
"hide_images",
"hide_unavailable_items",
"auto_add_item_to_cart",
"item_groups",
"column_break_16",
"update_stock",
"ignore_pricing_rule",
"allow_rate_change",
"allow_discount_change",
"section_break_23",
"item_groups",
"column_break_25",
"customer_groups",
"section_break_16",
"print_format",
@ -309,6 +313,7 @@
"default": "1",
"fieldname": "update_stock",
"fieldtype": "Check",
"hidden": 1,
"label": "Update Stock",
"read_only": 1
},
@ -329,13 +334,34 @@
"fieldname": "auto_add_item_to_cart",
"fieldtype": "Check",
"label": "Automatically Add Filtered Item To Cart"
},
{
"default": "0",
"fieldname": "allow_rate_change",
"fieldtype": "Check",
"label": "Allow User to Edit Rate"
},
{
"default": "0",
"fieldname": "allow_discount_change",
"fieldtype": "Check",
"label": "Allow User to Edit Discount"
},
{
"collapsible": 1,
"fieldname": "section_break_23",
"fieldtype": "Section Break"
},
{
"fieldname": "column_break_25",
"fieldtype": "Column Break"
}
],
"icon": "icon-cog",
"idx": 1,
"index_web_pages_for_search": 1,
"links": [],
"modified": "2020-12-10 13:59:28.877572",
"modified": "2021-01-06 14:42:41.713864",
"modified_by": "Administrator",
"module": "Accounts",
"name": "POS Profile",

View File

@ -435,7 +435,9 @@ class SalesInvoice(SellingController):
if not for_validate and not self.customer:
self.customer = pos.customer
self.ignore_pricing_rule = pos.ignore_pricing_rule
if not for_validate:
self.ignore_pricing_rule = pos.ignore_pricing_rule
if pos.get('account_for_change_amount'):
self.account_for_change_amount = pos.get('account_for_change_amount')

View File

@ -302,6 +302,7 @@ class AccountsController(TransactionBase):
args["doctype"] = self.doctype
args["name"] = self.name
args["child_docname"] = item.name
args["ignore_pricing_rule"] = self.ignore_pricing_rule if hasattr(self, 'ignore_pricing_rule') else 0
if not args.get("transaction_date"):
args["transaction_date"] = args.get("posting_date")

View File

@ -262,6 +262,7 @@ def make_return_doc(doctype, source_name, target_doc=None):
if doc.get("is_return"):
if doc.doctype == 'Sales Invoice' or doc.doctype == 'POS Invoice':
doc.consolidated_invoice = ""
doc.set('payments', [])
for data in source.payments:
paid_amount = 0.00

View File

@ -469,13 +469,19 @@ class SellingController(StockController):
non_stock_items = [d.item_code, d.description]
if frappe.db.get_value("Item", d.item_code, "is_stock_item") == 1:
duplicate_items_msg = _("Item {0} entered multiple times.").format(frappe.bold(d.item_code))
duplicate_items_msg += "<br><br>"
duplicate_items_msg += _("Please enable {} in {} to allow same item in multiple rows").format(
frappe.bold("Allow Item to Be Added Multiple Times in a Transaction"),
get_link_to_form("Selling Settings", "Selling Settings")
)
if stock_items in check_list:
frappe.throw(_("Note: Item {0} entered multiple times").format(d.item_code))
frappe.throw(duplicate_items_msg)
else:
check_list.append(stock_items)
else:
if non_stock_items in chk_dupl_itm:
frappe.throw(_("Note: Item {0} entered multiple times").format(d.item_code))
frappe.throw(duplicate_items_msg)
else:
chk_dupl_itm.append(non_stock_items)

View File

@ -107,7 +107,7 @@ class calculate_taxes_and_totals(object):
elif item.discount_amount and item.pricing_rules:
item.rate = item.price_list_rate - item.discount_amount
if item.doctype in ['Quotation Item', 'Sales Order Item', 'Delivery Note Item', 'Sales Invoice Item']:
if item.doctype in ['Quotation Item', 'Sales Order Item', 'Delivery Note Item', 'Sales Invoice Item', 'POS Invoice Item']:
item.rate_with_margin, item.base_rate_with_margin = self.calculate_margin(item)
if flt(item.rate_with_margin) > 0:
item.rate = flt(item.rate_with_margin * (1.0 - (item.discount_percentage / 100.0)), item.precision("rate"))

View File

@ -44,6 +44,7 @@ class TestMpesaSettings(unittest.TestCase):
create_mpesa_settings(payment_gateway_name="Payment")
mpesa_account = frappe.db.get_value("Payment Gateway Account", {"payment_gateway": 'Mpesa-Payment'}, "payment_account")
frappe.db.set_value("Account", mpesa_account, "account_currency", "KES")
frappe.db.set_value("Customer", "_Test Customer", "default_currency", "KES")
pos_invoice = create_pos_invoice(do_not_submit=1)
pos_invoice.append("payments", {'mode_of_payment': 'Mpesa-Payment', 'account': mpesa_account, 'amount': 500})
@ -69,6 +70,8 @@ class TestMpesaSettings(unittest.TestCase):
self.assertEquals(pos_invoice.mpesa_receipt_number, "LGR7OWQX0R")
self.assertEquals(integration_request.status, "Completed")
frappe.db.set_value("Customer", "_Test Customer", "default_currency", "")
def create_mpesa_settings(payment_gateway_name="Express"):
if frappe.db.exists("Mpesa Settings", payment_gateway_name):
return frappe.get_doc("Mpesa Settings", payment_gateway_name)

View File

@ -677,7 +677,7 @@ erpnext.patches.v13_0.move_tax_slabs_from_payroll_period_to_income_tax_slab #123
erpnext.patches.v12_0.fix_quotation_expired_status
erpnext.patches.v12_0.update_appointment_reminder_scheduler_entry
erpnext.patches.v12_0.rename_pos_closing_doctype
erpnext.patches.v13_0.replace_pos_payment_mode_table
erpnext.patches.v13_0.replace_pos_payment_mode_table #2020-12-29
erpnext.patches.v12_0.remove_duplicate_leave_ledger_entries #2020-05-22
erpnext.patches.v13_0.patch_to_fix_reverse_linking_in_additional_salary_encashment_and_incentive
execute:frappe.reload_doc("HR", "doctype", "Employee Advance")
@ -743,6 +743,7 @@ erpnext.patches.v13_0.updates_for_multi_currency_payroll
erpnext.patches.v13_0.create_leave_policy_assignment_based_on_employee_current_leave_policy
erpnext.patches.v13_0.add_po_to_global_search
erpnext.patches.v13_0.update_returned_qty_in_pr_dn
erpnext.patches.v13_0.create_uae_pos_invoice_fields
erpnext.patches.v13_0.update_project_template_tasks
erpnext.patches.v13_0.set_company_in_leave_ledger_entry
erpnext.patches.v13_0.convert_qi_parameter_to_link_field

View File

@ -0,0 +1,14 @@
# Copyright (c) 2019, Frappe and Contributors
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
import frappe
from erpnext.regional.united_arab_emirates.setup import make_custom_fields
def execute():
company = frappe.get_all('Company', filters = {'country': ['in', ['Saudi Arabia', 'United Arab Emirates']]})
if not company:
return
make_custom_fields()

View File

@ -6,12 +6,10 @@ from __future__ import unicode_literals
import frappe
def execute():
frappe.reload_doc("accounts", "doctype", "POS Payment Method")
frappe.reload_doc("accounts", "doctype", "pos_payment_method")
pos_profiles = frappe.get_all("POS Profile")
for pos_profile in pos_profiles:
if not pos_profile.get("payments"): return
payments = frappe.db.sql("""
select idx, parentfield, parenttype, parent, mode_of_payment, `default` from `tabSales Invoice Payment` where parent=%s
""", pos_profile.name, as_dict=1)

View File

@ -110,9 +110,11 @@ def make_custom_fields():
'Purchase Order': purchase_invoice_fields + invoice_fields,
'Purchase Receipt': purchase_invoice_fields + invoice_fields,
'Sales Invoice': sales_invoice_fields + invoice_fields,
'POS Invoice': sales_invoice_fields + invoice_fields,
'Sales Order': sales_invoice_fields + invoice_fields,
'Delivery Note': sales_invoice_fields + invoice_fields,
'Sales Invoice Item': invoice_item_fields + delivery_date_field + [is_zero_rated, is_exempt],
'POS Invoice Item': invoice_item_fields + delivery_date_field + [is_zero_rated, is_exempt],
'Purchase Invoice Item': invoice_item_fields,
'Sales Order Item': invoice_item_fields,
'Delivery Note Item': invoice_item_fields,

View File

@ -69,6 +69,10 @@ erpnext.PointOfSale.Controller = class {
dialog.fields_dict.balance_details.grid.refresh();
});
}
const pos_profile_query = {
query: 'erpnext.accounts.doctype.pos_profile.pos_profile.pos_profile_query',
filters: { company: frappe.defaults.get_default('company') }
}
const dialog = new frappe.ui.Dialog({
title: __('Create POS Opening Entry'),
static: true,
@ -80,6 +84,7 @@ erpnext.PointOfSale.Controller = class {
{
fieldtype: 'Link', label: __('POS Profile'),
options: 'POS Profile', fieldname: 'pos_profile', reqd: 1,
get_query: () => pos_profile_query,
onchange: () => fetch_pos_payment_methods()
},
{
@ -124,9 +129,8 @@ erpnext.PointOfSale.Controller = class {
});
frappe.db.get_doc("POS Profile", this.pos_profile).then((profile) => {
Object.assign(this.settings, profile);
this.settings.customer_groups = profile.customer_groups.map(group => group.customer_group);
this.settings.hide_images = profile.hide_images;
this.settings.auto_add_item_to_cart = profile.auto_add_item_to_cart;
this.make_app();
});
}
@ -255,11 +259,9 @@ erpnext.PointOfSale.Controller = class {
get_frm: () => this.frm,
cart_item_clicked: (item_code, batch_no, uom) => {
const item_row = this.frm.doc.items.find(
i => i.item_code === item_code
&& i.uom === uom
&& (!batch_no || (batch_no && i.batch_no === batch_no))
);
const search_field = batch_no ? 'batch_no' : 'item_code';
const search_value = batch_no || item_code;
const item_row = this.frm.doc.items.find(i => i[search_field] === search_value && i.uom === uom);
this.item_details.toggle_item_details_section(item_row);
},
@ -281,6 +283,7 @@ erpnext.PointOfSale.Controller = class {
init_item_details() {
this.item_details = new erpnext.PointOfSale.ItemDetails({
wrapper: this.$components_wrapper,
settings: this.settings,
events: {
get_frm: () => this.frm,
@ -415,6 +418,11 @@ erpnext.PointOfSale.Controller = class {
() => this.item_selector.toggle_component(true)
]);
},
delete_order: (name) => {
frappe.model.delete_doc(this.frm.doc.doctype, name, () => {
this.recent_order_list.refresh_list();
});
},
new_order: () => {
frappe.run_serially([
() => frappe.dom.freeze(),
@ -696,14 +704,14 @@ erpnext.PointOfSale.Controller = class {
frappe.dom.freeze();
const { doctype, name, current_item } = this.item_details;
frappe.model.set_value(doctype, name, 'qty', 0);
this.frm.script_manager.trigger('qty', doctype, name).then(() => {
frappe.model.clear_doc(doctype, name);
this.update_cart_html(current_item, true);
this.item_details.toggle_item_details_section(undefined);
frappe.dom.unfreeze();
})
frappe.model.set_value(doctype, name, 'qty', 0)
.then(() => {
frappe.model.clear_doc(doctype, name);
this.update_cart_html(current_item, true);
this.item_details.toggle_item_details_section(undefined);
frappe.dom.unfreeze();
})
.catch(e => console.log(e));
}
}

View File

@ -5,6 +5,8 @@ erpnext.PointOfSale.ItemCart = class {
this.customer_info = undefined;
this.hide_images = settings.hide_images;
this.allowed_customer_groups = settings.customer_groups;
this.allow_rate_change = settings.allow_rate_change;
this.allow_discount_change = settings.allow_discount_change;
this.init_component();
}
@ -201,7 +203,7 @@ erpnext.PointOfSale.ItemCart = class {
me.events.checkout();
me.toggle_checkout_btn(false);
me.$add_discount_elem.removeClass("d-none");
me.allow_discount_change && me.$add_discount_elem.removeClass("d-none");
});
this.$totals_section.on('click', '.edit-cart-btn', () => {
@ -479,11 +481,15 @@ erpnext.PointOfSale.ItemCart = class {
update_totals_section(frm) {
if (!frm) frm = this.events.get_frm();
this.render_net_total(frm.doc.base_net_total);
this.render_grand_total(frm.doc.base_grand_total);
this.render_net_total(frm.doc.net_total);
this.render_grand_total(frm.doc.grand_total);
const taxes = frm.doc.taxes.map(t => { return { description: t.description, rate: t.rate }})
this.render_taxes(frm.doc.base_total_taxes_and_charges, taxes);
const taxes = frm.doc.taxes.map(t => {
return {
description: t.description, rate: t.rate
}
});
this.render_taxes(frm.doc.total_taxes_and_charges, taxes);
}
render_net_total(value) {
@ -545,7 +551,7 @@ erpnext.PointOfSale.ItemCart = class {
get_cart_item({ item_code, batch_no, uom }) {
const batch_attr = `[data-batch-no="${escape(batch_no)}"]`;
const item_code_attr = `[data-item-code="${escape(item_code)}"]`;
const uom_attr = `[data-uom=${escape(uom)}]`;
const uom_attr = `[data-uom="${escape(uom)}"]`;
const item_selector = batch_no ?
`.cart-item-wrapper${batch_attr}${uom_attr}` : `.cart-item-wrapper${item_code_attr}${uom_attr}`;
@ -667,7 +673,7 @@ erpnext.PointOfSale.ItemCart = class {
update_selector_value_in_cart_item(selector, value, item) {
const $item_to_update = this.get_cart_item(item);
$item_to_update.attr(`data-${selector}`, value);
$item_to_update.attr(`data-${selector}`, escape(value));
}
toggle_checkout_btn(show_checkout) {
@ -702,14 +708,26 @@ erpnext.PointOfSale.ItemCart = class {
on_numpad_event($btn) {
const current_action = $btn.attr('data-button-value');
const action_is_field_edit = ['qty', 'discount_percentage', 'rate'].includes(current_action);
this.highlight_numpad_btn($btn, current_action);
const action_is_allowed = action_is_field_edit ? (
(current_action == 'rate' && this.allow_rate_change) ||
(current_action == 'discount_percentage' && this.allow_discount_change) ||
(current_action == 'qty')) : true;
const action_is_pressed_twice = this.prev_action === current_action;
const first_click_event = !this.prev_action;
const field_to_edit_changed = this.prev_action && this.prev_action != current_action;
if (action_is_field_edit) {
if (!action_is_allowed) {
const label = current_action == 'rate' ? 'Rate'.bold() : 'Discount'.bold();
const message = __('Editing {0} is not allowed as per POS Profile settings', [label]);
frappe.show_alert({
indicator: 'red',
message: message
});
frappe.utils.play_sound("error");
return;
}
if (first_click_event || field_to_edit_changed) {
this.prev_action = current_action;
@ -753,6 +771,7 @@ erpnext.PointOfSale.ItemCart = class {
this.numpad_value = current_action;
}
this.highlight_numpad_btn($btn, current_action);
this.events.numpad_event(this.numpad_value, this.prev_action);
}

View File

@ -1,7 +1,9 @@
erpnext.PointOfSale.ItemDetails = class {
constructor({ wrapper, events }) {
constructor({ wrapper, events, settings }) {
this.wrapper = wrapper;
this.events = events;
this.allow_rate_change = settings.allow_rate_change;
this.allow_discount_change = settings.allow_discount_change;
this.current_item = {};
this.init_component();
@ -207,17 +209,27 @@ erpnext.PointOfSale.ItemDetails = class {
bind_custom_control_change_event() {
const me = this;
if (this.rate_control) {
this.rate_control.df.onchange = function() {
if (this.value || flt(this.value) === 0) {
me.events.form_updated(me.doctype, me.name, 'rate', this.value).then(() => {
const item_row = frappe.get_doc(me.doctype, me.name);
const doc = me.events.get_frm().doc;
me.$item_price.html(format_currency(item_row.rate, doc.currency));
me.render_discount_dom(item_row);
});
}
if (this.allow_rate_change) {
this.rate_control.df.onchange = function() {
if (this.value || flt(this.value) === 0) {
me.events.form_updated(me.doctype, me.name, 'rate', this.value).then(() => {
const item_row = frappe.get_doc(me.doctype, me.name);
const doc = me.events.get_frm().doc;
me.$item_price.html(format_currency(item_row.rate, doc.currency));
me.render_discount_dom(item_row);
});
}
};
} else {
this.rate_control.df.read_only = 1;
}
this.rate_control.refresh();
}
if (this.discount_percentage_control && !this.allow_discount_change) {
this.discount_percentage_control.df.read_only = 1;
this.discount_percentage_control.refresh();
}
if (this.warehouse_control) {
@ -294,8 +306,16 @@ erpnext.PointOfSale.ItemDetails = class {
}
frappe.model.on("POS Invoice Item", "*", (fieldname, value, item_row) => {
const { item_code, batch_no, uom } = this.current_item;
const item_code_is_same = item_code === item_row.item_code;
const batch_is_same = batch_no == item_row.batch_no;
const uom_is_same = uom === item_row.uom;
// check if current_item is same as item_row
const item_is_same = item_code_is_same && batch_is_same && uom_is_same ? true : false;
const field_control = me[`${fieldname}_control`];
if (field_control) {
if (item_is_same && field_control && field_control.get_value() !== value) {
field_control.set_value(value);
cur_pos.update_cart_html(item_row);
}

View File

@ -265,6 +265,14 @@ erpnext.PointOfSale.PastOrderSummary = class {
this.$summary_wrapper.addClass('d-none');
});
this.$summary_container.on('click', '.delete-btn', () => {
this.events.delete_order(this.doc.name);
this.show_summary_placeholder();
// this.toggle_component(false);
// this.$component.find('.no-summary-placeholder').removeClass('d-none');
// this.$summary_wrapper.addClass('d-none');
});
this.$summary_container.on('click', '.new-btn', () => {
this.events.new_order();
this.toggle_component(false);
@ -401,7 +409,7 @@ erpnext.PointOfSale.PastOrderSummary = class {
return [{ condition: true, visible_btns: ['Print Receipt', 'Email Receipt', 'New Order'] }];
return [
{ condition: this.doc.docstatus === 0, visible_btns: ['Edit Order'] },
{ condition: this.doc.docstatus === 0, visible_btns: ['Edit Order', 'Delete Order'] },
{ condition: !this.doc.is_return && this.doc.docstatus === 1, visible_btns: ['Print Receipt', 'Email Receipt', 'Return']},
{ condition: this.doc.is_return && this.doc.docstatus === 1, visible_btns: ['Print Receipt', 'Email Receipt']}
];

View File

@ -672,13 +672,14 @@ class Item(WebsiteGenerator):
if not records: return
document = _("Stock Reconciliation") if len(records) == 1 else _("Stock Reconciliations")
msg = _("The items {0} and {1} are present in the following {2} : <br>"
.format(frappe.bold(old_name), frappe.bold(new_name), document))
msg = _("The items {0} and {1} are present in the following {2} : ").format(
frappe.bold(old_name), frappe.bold(new_name), document)
msg += '<br>'
msg += ', '.join([get_link_to_form("Stock Reconciliation", d.parent) for d in records]) + "<br><br>"
msg += _("Note: To merge the items, create a separate Stock Reconciliation for the old item {0}"
.format(frappe.bold(old_name)))
msg += _("Note: To merge the items, create a separate Stock Reconciliation for the old item {0}").format(
frappe.bold(old_name))
frappe.throw(_(msg), title=_("Merge not allowed"))
@ -971,7 +972,7 @@ class Item(WebsiteGenerator):
frappe.throw(_("As there are existing transactions against item {0}, you can not change the value of {1}").format(self.name, frappe.bold(self.meta.get_label(field))))
def check_if_linked_document_exists(self, field):
linked_doctypes = ["Delivery Note Item", "Sales Invoice Item", "Purchase Receipt Item",
linked_doctypes = ["Delivery Note Item", "Sales Invoice Item", "POS Invoice Item", "Purchase Receipt Item",
"Purchase Invoice Item", "Stock Entry Detail", "Stock Reconciliation Item"]
# For "Is Stock Item", following doctypes is important

View File

@ -19,7 +19,7 @@ from erpnext.stock.doctype.item_manufacturer.item_manufacturer import get_item_m
from six import string_types, iteritems
sales_doctypes = ['Quotation', 'Sales Order', 'Delivery Note', 'Sales Invoice']
sales_doctypes = ['Quotation', 'Sales Order', 'Delivery Note', 'Sales Invoice', 'POS Invoice']
purchase_doctypes = ['Material Request', 'Supplier Quotation', 'Purchase Order', 'Purchase Receipt', 'Purchase Invoice']
@frappe.whitelist()