def set_item_prices(items, posting_date, posting_time): get_rate = compose( excepts(IndexError, partial(get, 1), lambda __: None), excepts(StopIteration, first, lambda __: []), excepts(TypeError, json.loads, lambda __: []), lambda x: x.stock_queue, lambda x: get_previous_sle({ "item_code": x, "posting_date": posting_date, "posting_time": posting_time }), ) selling_price_list = frappe.db.get_single_value("Selling Settings", "selling_price_list") def get_price(item_code): get_first = compose(partial(get, "name"), excepts(StopIteration, first, lambda __: {})) prices = frappe.db.sql( """ SELECT name FROM `tabItem Price` WHERE item_code = %(item_code)s AND price_list = %(price_list)s AND IFNULL(uom, '') = '' """, values={ "item_code": item_code, "price_list": selling_price_list }, as_dict=1, ) if len(prices) > 1: frappe.throw( frappe._( "Cannot set {} Item Price because multiple prices exists"). format(selling_price_list)) item_price = get_first(prices) return frappe.get_doc("Item Price", item_price) if item_price else None def has_margin_price(item_code): return frappe.db.get_value("Item", item_code, "vn_has_margin_price") for item in items: if has_margin_price(item.item_code): rate = get_rate(item.item_code) if rate: item_price = get_price(item.item_code) if item_price and item_price.price_list_rate != rate: item_price.price_list_rate = rate item_price.save()
def _set_sales_orders(rows): get_orders = compose( partial(groupby, "invoice"), partial(unique, key=lambda x: x.get("invoice")), lambda x: frappe.db.sql( """ SELECT sii.parent AS invoice, sii.sales_order AS sales_order, so.workflow_state AS order_status FROM `tabSales Invoice Item` AS sii LEFT JOIN `tabSales Order` AS so ON so.name = sii.sales_order WHERE sii.parent IN %(invoices)s """, values={"invoices": x}, as_dict=1, ), list, unique, partial(pluck, "invoice"), ) orders = get_orders(rows) set_sales_order = compose( excepts(StopIteration, first, lambda _: {}), lambda x: orders.get(x, []), lambda x: x.get("invoice"), ) def fn(row): return merge(row, set_sales_order(row)) return fn
def get_mop_amount(mode_of_payment, payments=[]): return compose( partial(get, "amount"), excepts(StopIteration, first, lambda x: {"amount": 0}), partial(filter, lambda x: x.get("mode_of_payment") == mode_of_payment), )(payments)
def get_standard_prices(item_code): buying_price_list = frappe.db.get_single_value("Buying Settings", "buying_price_list") selling_price_list = frappe.db.get_single_value("Selling Settings", "selling_price_list") stock_uom = frappe.db.get_value("Item", item_code, "stock_uom") get_price = compose( lambda x: x.get("price_list_rate"), excepts(StopIteration, first, lambda _0: {}), lambda x: frappe.db.sql( """ SELECT price_list_rate FROM `tabItem Price` WHERE item_code = %(item_code)s AND price_list = %(price_list)s AND IFNULL(uom, '') IN ('', %(stock_uom)s) AND IFNULL(customer, '') = '' """, values={ "item_code": item_code, "price_list": x, "stock_uom": stock_uom }, as_dict=1, ), ) return { "selling_price": get_price(selling_price_list), "buying_price": get_price(buying_price_list), }
def _get_payments(args): payments = frappe.db.sql( """ SELECT sip.mode_of_payment AS mode_of_payment, sip.type AS type, SUM(sip.base_amount) AS amount, sip.mop_currency AS mop_currency, SUM(sip.mop_amount) AS mop_amount FROM `tabSales Invoice Payment` AS sip LEFT JOIN `tabSales Invoice` AS si ON sip.parent = si.name WHERE sip.parenttype = 'Sales Invoice' AND {clauses} GROUP BY sip.mode_of_payment """.format(clauses=_get_clauses()), values=args, as_dict=1, ) default_mop = compose( excepts(StopIteration, first, lambda __: None), partial(pluck, "mode_of_payment"), frappe.get_all, )( "Sales Invoice Payment", fields=["mode_of_payment"], filters={ "parenttype": "POS Profile", "parent": args.get("pos_profile"), "default": 1, }, ) return _correct_mop_amounts(payments, default_mop)
def _validate_cashback(doc): cashback_mop = "Cashback" if cashback_mop not in [ x.mode_of_payment for x in doc.payments if x.amount != 0 ]: return if not doc.os_cashback_receipt: frappe.throw( _("Cashback Receipt required if using Mode of Payment {}".format( frappe.bold(cashback_mop)))) get_cb_redeemed_amt = compose( excepts(StopIteration, first, lambda _: 0), lambda _=None: [x.amount for x in doc.payments if x.mode_of_payment == cashback_mop], ) redeemed_amt = get_cb_redeemed_amt() balance_amt, expiry_date = frappe.db.get_value( "Cashback Receipt", doc.os_cashback_receipt, ["balance_amount", "expiry_date"]) if redeemed_amt > balance_amt: frappe.throw( _("Redeemed cashback amount cannot be greater than available balance " "{}.".format( frappe.bold( frappe.utils.fmt_money(balance_amt, currency=doc.currency))))) if getdate(doc.posting_date) > expiry_date: frappe.throw(_("Cashback Receipt has expired."))
def get_pos_data(): from erpnext.accounts.doctype.sales_invoice.pos import get_pos_data get_price = compose( partial(get, "price_list_rate", default=0), excepts(StopIteration, first, lambda __: {}), ) get_price_list_data = compose(partial(valmap, get_price), _get_default_item_prices) def add_discounts(items): item_codes = compose(list, partial(pluck, "name"))(items) max_discounts_by_item = compose(partial(key_by, "name"), frappe.db.sql)( """ SELECT name, max_discount FROM `tabItem` WHERE item_code IN %(item_codes)s """, values={"item_codes": item_codes}, as_dict=1, ) return [merge(x, max_discounts_by_item.get(x.get("name")), {}) for x in items] data = get_pos_data() return merge( data, {"price_list_data": get_price_list_data(data.get("doc").selling_price_list)}, {"items": add_discounts(data.get("items"))}, )
def excepting_pipe(data, *funcs): for func in funcs: data = excepts(Exception, func, lambda _: _)(data) if isinstance(data, Exception): # Modify the error object to preserve the function name where it occurred # A generic error class would be better if hasattr(func, '__code__'): if hasattr(func, 'args'): print( f'Exception occurred in excepting pipe function {repr(func.__code__), func.args}: {data}' ) data.args = ( f'{repr(func.__code__), func.args}: {data.args[0]}', ) else: print( f'Exception occurred in excepting pipe function {repr(func.__code__)}: {data}' ) data.args = (f'{repr(func.__code__)}: {data.args[0]}', ) else: if hasattr(func, 'args'): print( f'Exception occurred in excepting pipe function {repr(func.__name__), func.args}: {data}' ) data.args = ( f'{repr(func.__name__), func.args}: {data.args[0]}', ) else: print( f'Exception occurred in excepting pipe function {repr(func.__name__)}: {data}' ) data.args = (f'{repr(func.__name__)}: {data.args[0]}', ) return data return data
def get_cashback_program(branch, posting_date): program_names = [ x.get("name") for x in frappe.db.sql( """ SELECT cp.name AS name FROM `tabCashback Program` AS cp LEFT JOIN `tabCashback Program Branch` AS cpb ON cpb.parent = cp.name WHERE cp.disabled = 0 AND cpb.branch = %(branch)s AND %(posting_date)s BETWEEN cp.from_date AND IFNULL(cp.to_date, '9999-12-31') """, values={ "branch": branch, "posting_date": posting_date }, as_dict=1, ) ] if len(program_names) > 1: frappe.throw( frappe._( "Something is wrong. More than one Cashback Program found.")) get_program = compose( lambda x: frappe.get_doc("Cashback Program", x) if x else None, excepts(StopIteration, first, lambda x: None), ) return get_program(program_names)
def translate_exception(func: Callable, exc1: Exception, exc2: Exception): """A functional try/except block: if `func` fails with `exc1`, raise `exc2`. >>> from gamla import functional_generic >>> functional_generic.pipe(iter([]), translate_exception(next, StopIteration, ValueError)) ValueError Note: `func` is assumed to be unary.""" return toolz.excepts(exc1, func, make_raise(exc2))
def _county_fips_name(fips): return pipe( Granularity.COUNTY, geo_data, curried.get("features"), curry(filter, lambda region: region["id"] == fips), excepts( StopIteration, lambda x: pipe(x, first, curried.get_in(["properties", "NAME"])), lambda _: None))
def _get_trainer(member, subscriptions): training_sub = compose( excepts(StopIteration, first, lambda __: None), partial(filter, lambda x: x.get("is_training") == 1), )(subscriptions) if not training_sub: return None return get_last(member, subscription_item=training_sub.get("item"))
def get_form_collected(mop): existing = compose( excepts(StopIteration, first, lambda x: None), partial(filter, lambda x: x.mode_of_payment == mop), )(existing_payments) if not existing or existing.collected_amount == existing.expected_amount: return {} return {"collected_amount": existing.collected_amount}
def track_exceptions(f, caught, default=None): """ Decorate ``f`` with a function that traps exceptions and appends them to ``caught``, returning ``default`` in their place. """ def _catch(_): caught.append(sys.exc_info()) return default return excepts(Exception, f, _catch)
def get_ref_so_date(sales_invoice): get_transaction_dates = compose( excepts(ValueError, min, lambda x: None), partial( map, lambda x: frappe.db.get_value("Sales Order", x, "transaction_date") ), _get_sales_orders, ) return get_transaction_dates(sales_invoice)
def set_or_create_batch(doc, method): def set_existing_batch(item): if item.os_expiry_date and not item.batch_no: has_batch_no, has_expiry_date = frappe.db.get_value( "Item", item.item_code, ["has_batch_no", "has_expiry_date"]) if has_batch_no and has_expiry_date: batch_no = frappe.db.exists( "Batch", { "item": item.item_code, "expiry_date": item.os_expiry_date }, ) item.batch_no = batch_no get_batch_in_previous_items = compose( lambda x: x.get("batch_no"), excepts(StopIteration, first, lambda _: {}), lambda x: filter( lambda item: item.idx < x.idx and item.item_code == x.item_code and item.pb_expiry_date == x.pb_expiry_date, doc.items, ), ) def create_new_batch(item): warehouse = "t_warehouse" if doc.doctype == "Stock Entry" else "warehouse" if item.get(warehouse) and item.os_expiry_date and not item.batch_no: has_batch_no, create_new_batch, has_expiry_date = frappe.db.get_value( "Item", item.item_code, ["has_batch_no", "create_new_batch", "has_expiry_date"], ) if has_batch_no and create_new_batch and has_expiry_date: batch_in_items = get_batch_in_previous_items(item) if batch_in_items: item.batch_no = batch_in_items return batch = frappe.get_doc({ "doctype": "Batch", "item": item.item_code, "expiry_date": item.os_expiry_date, "supplier": doc.supplier, # "reference_doctype": doc.doctype, # "reference_name": doc.name, }).insert() item.batch_no = batch.name if doc._action == "save": map_resolved(set_existing_batch, doc.items) # TODO: when `before_validate` gets merged into master create_new_batch should # run when doc._action == 'submit'. # also update `hooks.py` to use `before_validate` instead of the current # `before_save` method map_resolved(create_new_batch, doc.items)
def _set_consumption(sles, periods): def groupby_filter(sl): def fn(p): return p.get("start_date") <= sl.get("posting_date") <= p.get( "end_date") return fn groupby_fn = compose( partial(get, "key", default=None), excepts(StopIteration, first, lambda __: {}), partial(flip, filter, periods), groupby_filter, ) sles_grouped = groupby(groupby_fn, sles) summer = compose(operator.neg, sum, partial(pluck, "actual_qty")) def seg_filter(x): return lambda sl: sl.get("item_code") == x segregator_fns = map( lambda x: merge( x, { "seger": compose( summer, partial(flip, filter, get(x.get("key"), sles_grouped, [])), seg_filter, ) }, ), periods, ) def seg_reducer(item_code): def fn(a, p): key = get("key", p, None) seger = get("seger", p, lambda __: None) return merge(a, {key: seger(item_code)}) return fn total_fn = compose(summer, partial(flip, filter, sles), seg_filter) def fn(item): item_code = item.get("item_code") return merge( item, reduce(seg_reducer(item_code), segregator_fns, {}), {"total_consumption": total_fn(item_code)}, ) return fn
def before_submit(self): if not self.period_to: self.period_to = get_datetime() self.set_report_details() get_default_collected = compose( lambda x: x.collected_amount if x else 0, excepts(StopIteration, first, lambda x: None), partial(filter, lambda x: cint(x.is_default) == 1), ) self.closing_amount = self.opening_amount + get_default_collected(self.payments)
def get_item_rate(item_code, uom, price_list="Standard Selling"): get_price = compose( lambda x: x[1] if x else None, excepts(StopIteration, first, lambda __: None), get_item_price, ) return get_price( {"price_list": price_list, "uom": uom, "transaction_date": today()}, item_code, )
def _count_activations(customers, intervals): def groupby_filter(c): def fn(p): return (p.get("start_date") <= c.get("loyalty_activation_date") <= p.get("end_date")) return fn groupby_fn = compose( partial(get, "key", default=None), excepts(StopIteration, first, lambda __: {}), partial(flip, filter, intervals), groupby_filter, ) customers_grouped = groupby(groupby_fn, customers) def seg_filter(x): return lambda c: c.get("branch") == x segregator_fns = map( lambda x: merge( x, { "seger": compose( len, partial(flip, filter, get(x.get("key"), customers_grouped, [])), seg_filter, ) }, ), intervals, ) def seg_reducer(branch): def fn(a, p): key = get("key", p, None) seger = get("seger", p, lambda __: None) return merge(a, {key: seger(branch)}) return fn total_fn = compose(len, partial(flip, filter, customers), seg_filter) def fn(x): branch = x.get("branch") return merge( x, reduce(seg_reducer(branch), segregator_fns, {}), {"total": total_fn(branch)}, ) return fn
def _get_payments(args): sales_payments = frappe.db.sql( """ SELECT sip.mode_of_payment AS mode_of_payment, sip.type AS type, SUM(sip.base_amount) AS amount, sip.mop_currency AS mop_currency, SUM(sip.mop_amount) AS mop_amount FROM `tabSales Invoice Payment` AS sip LEFT JOIN `tabSales Invoice` AS si ON sip.parent = si.name WHERE sip.parenttype = 'Sales Invoice' AND {clauses} GROUP BY sip.mode_of_payment """.format( clauses=_get_clauses(args) ), values=args, as_dict=1, ) default_mop = compose( excepts(StopIteration, first, lambda __: None), partial(pluck, "mode_of_payment"), frappe.get_all, )( "Sales Invoice Payment", fields=["mode_of_payment"], filters={ "parenttype": "POS Profile", "parent": args.get("pos_profile"), "default": 1, }, ) collection_payments = frappe.db.sql( """ SELECT mode_of_payment, SUM(paid_amount) AS amount FROM `tabPayment Entry` WHERE docstatus = 1 AND company = %(company)s AND owner = %(user)s AND TIMESTAMP(posting_date, pb_posting_time) BETWEEN %(period_from)s AND %(period_to)s GROUP BY mode_of_payment """, values=args, as_dict=1, ) return ( _correct_mop_amounts(sales_payments, default_mop), _correct_mop_amounts(collection_payments, default_mop), )
def remove_snapshot( self, snap: ModelSnapshot) -> Union[Exception, ModelSnapshot]: if not self._snapshots.get(snap.id, None): raise Exception("remove_snapshot", f"Snapshot {snap.id} is not known") # remove container image # Todo: Fix issue with depending child images i = excepts(Exception, lambda image: self._d.images.get(image), lambda _: -1)(snap.new_container_image_name) excepts(Exception, lambda image: self._d.images.remove(image.id, force=True), lambda _: -1)(i) # Remove the method file from filesystem rmtree(str(snap.storage_path)) # Remove object from collection self._snapshots.pop(snap.id) return snap
def advance_wf(name): doc = frappe.get_doc("Sales Order", name) workflow_state = compose( lambda x: x.get("state"), excepts(StopIteration, first, lambda: {}), partial(filter, lambda x: x.get("action") == "Complete"), frappe.model.workflow.get_transitions, )(doc, workflow) if (doc and doc.delivery_status == "Fully Delivered" and doc.get(workflow.workflow_state_field) == workflow_state): apply_workflow(doc, "Complete")
def get_number_from_contact(contact): get_number = compose( lambda x: x.get("phone"), excepts(StopIteration, first, lambda __: {}), frappe.db.sql, ) return get_number( """ SELECT phone FROM `tabContact Phone` WHERE parent = %(parent)s AND is_primary_mobile_no = 1 """, values={"parent": contact}, as_dict=1, )
def pull_container_context(self, context: Union[ModelSnapshot, Result]) -> Union[ModelSnapshot, Result]: context = update_instance_status_rest(instance=context, new_status=f'Pull Model-Container from Registry') log_container_pull = "Started: {}\n".format(get_timestamp()) # Catch the exception if the image is not found (image will be build later) # log_container_pull += excepts(NotFound, # For debugging ignore errors from the registry and continue # TODO: Apply error handling log_container_pull += excepts(Exception, lambda image: self._d_low.pull(image), lambda _: 'image not present')(context.container_image_name) return dataclasses.replace(context, container_pull_logs=log_container_pull)
def _get_data(file_url): get_header = excepts(StopIteration, first, lambda _: []) get_rows = compose(list, partial(drop, 1)) if not file_url: return [], [] file = frappe.get_doc("File", {"file_url": file_url}) filename, file_extension = file.get_extension() if file_extension == ".xlsx": data = read_xlsx_file_from_attached_file(file_url=file_url) return get_header(data), get_rows(data) if file_extension == ".csv": data = read_csv_content(file.get_content()) return get_header(data), get_rows(data) frappe.throw(frappe._("Unsupported File Format"))
def get_pos_data(): from erpnext.accounts.doctype.sales_invoice.pos import get_pos_data get_price = compose( partial(get, "price_list_rate", default=0), excepts(StopIteration, first, lambda __: {}), ) get_price_list_data = compose(partial(valmap, get_price), _get_default_item_prices) data = get_pos_data() return merge( data, {"price_list_data": get_price_list_data(data.get("doc").selling_price_list)}, )
def on_update(doc, method): if doc.customer_primary_contact and not doc.mobile_no: get_number = compose( partial(get, "phone", default=None), excepts(StopIteration, first, lambda __: {}), frappe.db.sql, ) mobile_no = get_number( """ SELECT phone FROM `tabContact Phone` WHERE parent = %(parent)s AND is_primary_mobile_no = 1 LIMIT 1 """, values={"parent": doc.customer_primary_contact}, as_dict=1, ) frappe.db.set_value("Customer", doc.name, "mobile_no", mobile_no) doc.reload()
def get_amounts(doc): get_price_list_amount = compose( sum, partial( map, excepts( ZeroDivisionError, lambda x: x.amount / abs(x.amount) * max( flt(x.price_list_rate) * abs(flt(x.qty)), abs(flt(x.amount) )), lambda __: 0, ), ), ) total = get_price_list_amount(doc.items) # `doc.discount_amount` is negative discount_amount = doc.discount_amount + (doc.total - total) return {"total": total, "discount_amount": discount_amount}
def _set_cashback_balances(doc, cancel=False): get_cb_redeemed_amt = compose( excepts(StopIteration, first, lambda _: 0), lambda _=None: [ x.amount for x in doc.payments if x.mode_of_payment == "Cashback" ], ) redeemed_amt = get_cb_redeemed_amt() if redeemed_amt > 0: cashback_receipt = frappe.get_doc("Cashback Receipt", doc.os_cashback_receipt) if cancel: cashback_receipt.redemptions = [ x for x in cashback_receipt.redemptions if x.reference != doc.name ] else: cashback_receipt.append( "redemptions", {"reference": doc.name, "amount": redeemed_amt} ) cashback_receipt.save(ignore_permissions=True)