Skip to content

Commit

Permalink
Merge branch 'develop' into is-subcontracted-fieldtype
Browse files Browse the repository at this point in the history
  • Loading branch information
s-aga-r authored Apr 4, 2022
2 parents c4ef377 + 205c8c2 commit b67394d
Show file tree
Hide file tree
Showing 9 changed files with 117 additions and 75 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -745,6 +745,8 @@ def calculate_amounts(against_loan, posting_date, payment_type=""):
if payment_type == "Loan Closure":
amounts["payable_principal_amount"] = amounts["pending_principal_amount"]
amounts["interest_amount"] += amounts["unaccrued_interest"]
amounts["payable_amount"] = amounts["payable_principal_amount"] + amounts["interest_amount"]
amounts["payable_amount"] = (
amounts["payable_principal_amount"] + amounts["interest_amount"] + amounts["penalty_amount"]
)

return amounts
21 changes: 7 additions & 14 deletions erpnext/public/js/controllers/transaction.js
Original file line number Diff line number Diff line change
Expand Up @@ -403,17 +403,6 @@ erpnext.TransactionController = class TransactionController extends erpnext.taxe
var sms_man = new erpnext.SMSManager(this.frm.doc);
}

barcode(doc, cdt, cdn) {
const d = locals[cdt][cdn];
if (!d.barcode) {
// barcode cleared, remove item
d.item_code = "";
}
// flag required for circular triggers
d._triggerd_from_barcode = true;
this.item_code(doc, cdt, cdn);
}

item_code(doc, cdt, cdn) {
var me = this;
var item = frappe.get_doc(cdt, cdn);
Expand All @@ -431,9 +420,7 @@ erpnext.TransactionController = class TransactionController extends erpnext.taxe
this.frm.doc.doctype === 'Delivery Note') {
show_batch_dialog = 1;
}
if (!item._triggerd_from_barcode) {
item.barcode = null;
}
item.barcode = null;


if(item.item_code || item.barcode || item.serial_no) {
Expand Down Expand Up @@ -539,6 +526,12 @@ erpnext.TransactionController = class TransactionController extends erpnext.taxe
if(!d[k]) d[k] = v;
});

if (d.__disable_batch_serial_selector) {
// reset for future use.
d.__disable_batch_serial_selector = false;
return;
}

if (d.has_batch_no && d.has_serial_no) {
d.batch_no = undefined;
}
Expand Down
24 changes: 19 additions & 5 deletions erpnext/public/js/utils/barcode_scanner.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,7 @@ erpnext.utils.BarcodeScanner = class BarcodeScanner {
// batch_no: "LOT12", // present if batch was scanned
// serial_no: "987XYZ", // present if serial no was scanned
// }
this.scan_api =
opts.scan_api ||
"erpnext.selling.page.point_of_sale.point_of_sale.search_for_serial_or_batch_or_barcode_number";
this.scan_api = opts.scan_api || "erpnext.stock.utils.scan_barcode";
}

process_scan() {
Expand Down Expand Up @@ -52,14 +50,16 @@ erpnext.utils.BarcodeScanner = class BarcodeScanner {
return;
}

me.update_table(data.item_code, data.barcode, data.batch_no, data.serial_no);
me.update_table(data);
});
}

update_table(item_code, barcode, batch_no, serial_no) {
update_table(data) {
let cur_grid = this.frm.fields_dict[this.items_table_name].grid;
let row = null;

const {item_code, barcode, batch_no, serial_no} = data;

// Check if batch is scanned and table has batch no field
let batch_no_scan =
Boolean(batch_no) && frappe.meta.has_field(cur_grid.doctype, this.batch_no_field);
Expand All @@ -84,13 +84,27 @@ erpnext.utils.BarcodeScanner = class BarcodeScanner {
}

this.show_scan_message(row.idx, row.item_code);
this.set_selector_trigger_flag(row, data);
this.set_item(row, item_code);
this.set_serial_no(row, serial_no);
this.set_batch_no(row, batch_no);
this.set_barcode(row, barcode);
this.clean_up();
}

// batch and serial selector is reduandant when all info can be added by scan
// this flag on item row is used by transaction.js to avoid triggering selector
set_selector_trigger_flag(row, data) {
const {batch_no, serial_no, has_batch_no, has_serial_no} = data;

const require_selecting_batch = has_batch_no && !batch_no;
const require_selecting_serial = has_serial_no && !serial_no;

if (!(require_selecting_batch || require_selecting_serial)) {
row.__disable_batch_serial_selector = true;
}
}

set_item(row, item_code) {
const item_data = { item_code: item_code };
item_data[this.qty_field] = (row[this.qty_field] || 0) + 1;
Expand Down
27 changes: 4 additions & 23 deletions erpnext/selling/page/point_of_sale/point_of_sale.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,14 @@


import json
from typing import Dict, Optional

import frappe
from frappe.utils.nestedset import get_root_of

from erpnext.accounts.doctype.pos_invoice.pos_invoice import get_stock_availability
from erpnext.accounts.doctype.pos_profile.pos_profile import get_child_nodes, get_item_groups
from erpnext.stock.utils import scan_barcode


def search_by_term(search_term, warehouse, price_list):
Expand Down Expand Up @@ -150,29 +152,8 @@ def get_items(start, page_length, price_list, item_group, pos_profile, search_te


@frappe.whitelist()
def search_for_serial_or_batch_or_barcode_number(search_value):
# search barcode no
barcode_data = frappe.db.get_value(
"Item Barcode", {"barcode": search_value}, ["barcode", "parent as item_code"], as_dict=True
)
if barcode_data:
return barcode_data

# search serial no
serial_no_data = frappe.db.get_value(
"Serial No", search_value, ["name as serial_no", "item_code"], as_dict=True
)
if serial_no_data:
return serial_no_data

# search batch no
batch_no_data = frappe.db.get_value(
"Batch", search_value, ["name as batch_no", "item as item_code"], as_dict=True
)
if batch_no_data:
return batch_no_data

return {}
def search_for_serial_or_batch_or_barcode_number(search_value: str) -> Dict[str, Optional[str]]:
return scan_barcode(search_value)


def get_conditions(search_term):
Expand Down
15 changes: 0 additions & 15 deletions erpnext/stock/doctype/stock_entry/stock_entry.js
Original file line number Diff line number Diff line change
Expand Up @@ -646,21 +646,6 @@ frappe.ui.form.on('Stock Entry Detail', {
frm.events.calculate_basic_amount(frm, item);
},

barcode: function(doc, cdt, cdn) {
var d = locals[cdt][cdn];
if (d.barcode) {
frappe.call({
method: "erpnext.stock.get_item_details.get_item_code",
args: {"barcode": d.barcode },
callback: function(r) {
if (!r.exe){
frappe.model.set_value(cdt, cdn, "item_code", r.message);
}
}
});
}
},

uom: function(doc, cdt, cdn) {
var d = locals[cdt][cdn];
if(d.uom && d.item_code){
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -163,20 +163,7 @@ frappe.ui.form.on("Stock Reconciliation", {
});
}
},
set_item_code: function(doc, cdt, cdn) {
var d = frappe.model.get_doc(cdt, cdn);
if (d.barcode) {
frappe.call({
method: "erpnext.stock.get_item_details.get_item_code",
args: {"barcode": d.barcode },
callback: function(r) {
if (!r.exe){
frappe.model.set_value(cdt, cdn, "item_code", r.message);
}
}
});
}
},

set_amount_quantity: function(doc, cdt, cdn) {
var d = frappe.model.get_doc(cdt, cdn);
if (d.qty & d.valuation_rate) {
Expand Down Expand Up @@ -214,9 +201,6 @@ frappe.ui.form.on("Stock Reconciliation", {
});

frappe.ui.form.on("Stock Reconciliation Item", {
barcode: function(frm, cdt, cdn) {
frm.events.set_item_code(frm, cdt, cdn);
},

warehouse: function(frm, cdt, cdn) {
var child = locals[cdt][cdn];
Expand Down
3 changes: 3 additions & 0 deletions erpnext/stock/get_item_details.py
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,9 @@ def update_stock(args, out):
reserved_so = get_so_reservation_for_item(args)
out.serial_no = get_serial_no(out, args.serial_no, sales_order=reserved_so)

if not out.serial_no:
out.pop("serial_no", None)


def set_valuation_rate(out, args):
if frappe.db.exists("Product Bundle", args.item_code, cache=True):
Expand Down
31 changes: 31 additions & 0 deletions erpnext/stock/tests/test_utils.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import frappe
from frappe.tests.utils import FrappeTestCase

from erpnext.stock.doctype.item.test_item import make_item
from erpnext.stock.utils import scan_barcode


class TestStockUtilities(FrappeTestCase):
def test_barcode_scanning(self):
simple_item = make_item(properties={"barcodes": [{"barcode": "12399"}]})
self.assertEqual(scan_barcode("12399")["item_code"], simple_item.name)

batch_item = make_item(properties={"has_batch_no": 1, "create_new_batch": 1})
batch = frappe.get_doc(doctype="Batch", item=batch_item.name).insert()

batch_scan = scan_barcode(batch.name)
self.assertEqual(batch_scan["item_code"], batch_item.name)
self.assertEqual(batch_scan["batch_no"], batch.name)
self.assertEqual(batch_scan["has_batch_no"], 1)
self.assertEqual(batch_scan["has_serial_no"], 0)

serial_item = make_item(properties={"has_serial_no": 1})
serial = frappe.get_doc(
doctype="Serial No", item_code=serial_item.name, serial_no=frappe.generate_hash()
).insert()

serial_scan = scan_barcode(serial.name)
self.assertEqual(serial_scan["item_code"], serial_item.name)
self.assertEqual(serial_scan["serial_no"], serial.name)
self.assertEqual(serial_scan["has_batch_no"], 0)
self.assertEqual(serial_scan["has_serial_no"], 1)
49 changes: 49 additions & 0 deletions erpnext/stock/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@


import json
from typing import Dict, Optional

import frappe
from frappe import _
Expand Down Expand Up @@ -548,3 +549,51 @@ def check_pending_reposting(posting_date: str, throw_error: bool = True) -> bool
)

return bool(reposting_pending)


@frappe.whitelist()
def scan_barcode(search_value: str) -> Dict[str, Optional[str]]:

# search barcode no
barcode_data = frappe.db.get_value(
"Item Barcode",
{"barcode": search_value},
["barcode", "parent as item_code"],
as_dict=True,
)
if barcode_data:
return _update_item_info(barcode_data)

# search serial no
serial_no_data = frappe.db.get_value(
"Serial No",
search_value,
["name as serial_no", "item_code", "batch_no"],
as_dict=True,
)
if serial_no_data:
return _update_item_info(serial_no_data)

# search batch no
batch_no_data = frappe.db.get_value(
"Batch",
search_value,
["name as batch_no", "item as item_code"],
as_dict=True,
)
if batch_no_data:
return _update_item_info(batch_no_data)

return {}


def _update_item_info(scan_result: Dict[str, Optional[str]]) -> Dict[str, Optional[str]]:
if item_code := scan_result.get("item_code"):
if item_info := frappe.get_cached_value(
"Item",
item_code,
["has_batch_no", "has_serial_no"],
as_dict=True,
):
scan_result.update(item_info)
return scan_result

0 comments on commit b67394d

Please sign in to comment.