async def on_req_delete_node(self, node_id=None): if node_id is None: pass # deleting the node that is being inserted else: await self.db_obj.init(display=False, init_vals={'row_id': node_id}) if not await self.db_obj.getval('parent_id'): raise AibError(head='Error', body='Cannot delete root node') if await self.db_obj.getval('children'): raise AibError(head='Error', body='Cannot delete node with children') await self.db_obj.delete() self.session.responder.send_delete_node(self.ref, node_id)
async def claim_task(session, task_id): if task_id not in active_tasks: raise AibError( head='Claim task', body='Task {} already completed/cancelled'.format(task_id)) task, claimed_by = active_tasks[task_id] if claimed_by is not None: user_name = await db.cache.get_user_name(claimed_by.user_row_id) raise AibError(head='Claim task', body='Task {} already claimed by {}'.format( task.title, user_name)) active_tasks[task_id] = (task, session) bump_version() await task.start_task(session)
async def on_selected(self, node_id): # await self.db_obj.init(init_vals={'row_id': node_id}) await self.db_obj.select_row({'row_id': node_id}) if self.group is not None: node_type = await self.db_obj.getval('type') data_row_id = await self.db_obj.getval('data_row_id') node_type = await self.db_obj.getval('type') if node_type == 'group': # # await self.group.init(init_vals={'row_id': data_row_id}) # await self.group.select_row({'row_id': data_row_id}) raise AibError(head='Lookup', body='Cannot select {} here'.format( self.group.table_name)) else: # must be 'member' # await self.member.init(init_vals={'row_id': data_row_id}) await self.member.select_row({'row_id': data_row_id}) self.session.responder.send_end_form(self.form) await self.form.close_form() callback, caller, *args = self.form.callback state = 'completed' return_params = None await callback(caller, state, return_params, *args)
async def eval_exp(src, chk, tgt, db_obj, fld, value): if chk == 'pyfunc': if fld is None: # called from db.objects fld = await db_obj.getfld(src) # src is the field name to check src_val = await eval_elem(src, db_obj, fld, value) func_name = tgt if '.' in func_name: module_name, func_name = func_name.rsplit('.', 1) module = importlib.import_module(module_name) result = await getattr(module, func_name)(db_obj, fld, src_val) else: # e.g. check_not_null result = await globals()[func_name](db_obj, fld, src_val) if result not in (True, False): raise AibError( head='pyfunc error', body=f'pyfunc {func_name} must return True or False') else: src_val = await eval_elem(src, db_obj, fld, value) tgt_val = await eval_elem(tgt, db_obj, fld, value) # don't know what could go wrong here [2019-07-08] # try: # result = CHKS[chk](src_val, tgt_val) # except ValueError: # result = False result = CHKS[chk](src_val, tgt_val) return result
async def exch_rate(fld, xml, debug): code_xml, date_xml = xml # must be two elements curr_id = await globals()[code_xml.tag](fld, code_xml, debug) if curr_id is None: return None eff_date = await globals()[date_xml.tag](fld, date_xml, debug) if eff_date is None: return None curr_rates = await db.cache.get_curr_rates(fld.db_obj.company) col_names = ['rate'] where = [] where.append(('WHERE', '', 'currency_id', '=', curr_id, '')) where.append(('AND', '', 'eff_date', '<=', eff_date, '')) order = [('eff_date', True)] limit = 1 async with fld.db_obj.context.db_session.get_connection() as db_mem_conn: conn = db_mem_conn.db cur = await conn.full_select(curr_rates, col_names, where=where, order=order, limit=limit) try: rate, = await cur.__anext__() except StopAsyncIteration: raise AibError(head='Exchange rate', body='No exchange rate found') return rate
async def setup_balance_date(caller, xml): # called from ar_balances before_start_form fin_periods = await db.cache.get_adm_periods(caller.company) ledger_periods = await db.cache.get_ledger_periods( caller.company, *caller.context.mod_ledg_id) if not ledger_periods: raise AibError(head='Periods', body='No periods set up for {}'.format( caller.context.mod_ledg_id)) current_period = ledger_periods.current_period # set initial period_no to current_period today = dt.today() current_closing_date = fin_periods[current_period].closing_date if today > current_closing_date: balance_date = current_closing_date else: balance_date = today var = caller.data_objects['balance_date_vars'] await var.setval('balance_date', balance_date) await var.setval( 'settings', [ 'P', # select_method current_period, # period_no balance_date, ])
async def set_tran_lock(caller, xml): obj_name = xml.get('obj_name') tran_obj = caller.context.data_objects[obj_name] if not tran_obj.exists: return # only applies if amending an existing transaction # 'lock' is called 'before_start_form', 'unlock' is called 'on_close_form' # this assumes that one form instance amends only one transaction # if we have one form instance that amends a series of transactions, # this will not work key = (caller.company, tran_obj.db_table.data_tableid, await tran_obj.getval('row_id')) action = xml.get('action') if action == 'lock': with await tran_lock: if key in tran_locks: locking_caller = tran_locks[key] locking_user = await get_user_name( locking_caller.context.user_row_id) raise AibError( head='Transaction locked', body='{}: transaction is currently in use by {}'.format( tran_obj.db_table.short_descr, locking_user)) tran_locks[key] = caller elif action == 'unlock': if key in tran_locks: if tran_locks[key] is caller: del tran_locks[key]
async def get_mod_id(company, mod_id): # mod_id could be numeric, asking for module_id, or alpha, asking for module_row_id if mod_id is None: raise AibError(head='Module', body='Module id is None') with await mod_lock: if company not in mod_ids: mod_ids[company] = {} async with db_session.get_connection() as db_mem_conn: conn = db_mem_conn.db sql = f'SELECT row_id, module_id, descr FROM {company}.db_modules WHERE deleted_id = 0' async for row_id, module_id, descr in await conn.exec_sql(sql): mod_ids[company][row_id] = (module_id, descr) mod_ids[company][module_id] = row_id try: return mod_ids[company][mod_id] except KeyError: raise AibError(head='Module', body=f'"{mod_id}" not found')
async def check_wh_date(db_obj, fld, ledger_row_id): # called from various ledger_row_id col_checks using pyfunc if ledger_row_id is None: # no dflt_val for ledger_row_id return True # will be called after entry of ledger_row_id try: period_row_id = await db_obj.getval( 'tran_det_row_id>tran_row_id>period_row_id') except KeyError: period_row_id = await db_obj.getval('tran_row_id>period_row_id') module_row_id = await db.cache.get_mod_id(db_obj.company, 'in') ledger_periods = await db.cache.get_ledger_periods(db_obj.company, module_row_id, ledger_row_id) if ledger_periods is None: raise AibError(head=fld.col_defn.short_descr, body='Warehouse period not set up') if period_row_id not in ledger_periods: # if period_row_id == ledger_periods['curr'] + 1: # create new open period if period_row_id == ledger_periods.current_period + 1: # create new open period ledger_period = await db.objects.get_db_object( db.cache.cache_context, db_obj.company, 'in_ledger_periods') await ledger_period.init( init_vals={ 'ledger_row_id': ledger_row_id, 'period_row_id': period_row_id, 'state': 'open', }) await ledger_period.save() ledger_periods = await db.cache.get_ledger_periods( db_obj.company, module_row_id, ledger_row_id) if period_row_id not in ledger_periods: raise AibError(head=fld.col_defn.short_descr, body='Warehouse period not open') if ledger_periods[period_row_id].state not in ('current', 'open', 'reopened'): raise AibError(head=fld.col_defn.short_descr, body='Warehouse period is closed') return True
async def chk_constraint(caller, constraint, value=None, errmsg=None): # can be a column constraint (col_chk) or a table constraint (upd_chk or del_chk) try: db_obj = caller.db_obj # this is a column constraint fld = caller descr = caller.col_defn.short_descr except AttributeError: db_obj = caller # this is a table constraint fld = None descr = db_obj.db_table.short_descr result = await eval_expr(constraint, db_obj, fld, value) if result not in (True, False): raise AibError( head='constraint error', body=f'constraint {constraint} must return True or False') if result is False: raise AibError(head=descr, body=errmsg)
async def on_req_delete_node(self, node_id=None): if node_id is not None: # else deleting the node that is being inserted await self.db_obj.init(display=False, init_vals={'row_id': node_id}) if node_id == 1: raise AibError(head='Error', body='Cannot delete root node') node_type = await self.db_obj.getval('type') data_row_id = await self.db_obj.getval('data_row_id') if node_type == 'group': obj_to_delete = self.group else: # must be 'member' obj_to_delete = self.member if await obj_to_delete.getval('children'): raise AibError(head='Error', body='Cannot delete node with children') await obj_to_delete.delete() # self.db_obj.init(display=False) # await self.db_obj.setval('type', node_type) # await self.db_obj.setval('data_row_id', data_row_id) await self.db_obj.delete() self.session.responder.send_delete_node(self.ref, node_id)
async def dump_form_xml(caller, xml): # called from setup_form 'before_save' form_defn = caller.data_objects['form'] form_vars = caller.data_objects['form_vars'] frame_vars = caller.data_objects['frame_vars'] form_xml = etree.Element('form') form_xml.set('name', await form_defn.getval('form_name')) form_xml.set('title', await form_defn.getval('title')) await set_if_not_none(form_xml, form_vars, 'before_start_form') await set_if_not_none(form_xml, form_vars, 'after_start_form') await set_if_not_none(form_xml, form_vars, 'on_end_form') form_xml.append(await form_vars.getval('dbobj_xml')) form_xml.append(await form_vars.getval('memobj_xml')) form_xml.append(await form_vars.getval('inputs_xml')) form_xml.append(await form_vars.getval('outputs_xml')) frame_xml = etree.SubElement(form_xml, 'frame') await set_if_not_none(frame_xml, frame_vars, 'main_object') await set_if_not_none(frame_xml, frame_vars, 'obj_descr') frame_xml.append(await frame_vars.getval('toolbar_xml')) frame_xml.append(await frame_vars.getval('body_xml')) frame_xml.append(await frame_vars.getval('buttonrow_xml')) frame_xml.append(await frame_vars.getval('methods_xml')) inline_vars = caller.data_objects['inline_vars'] all_inline = inline_vars.select_many(where=[], order=[]) async for _ in all_inline: inline_xml = etree.SubElement(form_xml, 'inline_form') inline_xml.set('name', await inline_vars.getval('name')) inline_xml.set('title', await inline_vars.getval('title')) inline_xml.append(await inline_vars.getval('frame_xml')) # inline_params = await form_vars.getval('inline_xml') # for name, frame_xml in inline_params: # inline_xml = etree.SubElement(form_xml, 'inline_form') # inline_xml.set('name', name) # inline_xml.append(frame_xml) # validate result using schema try: etree.fromstring(etree.tostring(form_xml), parser=xsd_parser) except (etree.XMLSyntaxError, ValueError, TypeError) as e: raise AibError(head='XmlError', body=e.args[0]) # update form_definition with new form_xml await form_defn.setval('form_xml', form_xml) """
async def handle_unhandled_cust(): if 'ar_customers' not in caller.context.data_objects: caller.context.data_objects[ 'ar_customers'] = await db.objects.get_db_object( caller.context, caller.company, 'ar_customers') ar_cust = caller.context.data_objects['ar_customers'] if 'ar_stat_dates' not in caller.context.data_objects: caller.context.data_objects[ 'ar_stat_dates'] = await db.objects.get_db_object( caller.context, caller.company, 'ar_stat_dates') stat_dates = caller.context.data_objects['ar_stat_dates'] if 'ar_ledg_per' not in caller.context.data_objects: caller.context.data_objects[ 'ar_ledg_per'] = await db.objects.get_db_object( caller.context, caller.company, 'ar_ledger_periods') ledg_per = caller.context.data_objects['ar_ledg_per'] unhandled_cust = ar_cust.select_many( where=[['WHERE', '', 'current_stat_date', 'IS', None, '']], order=[]) async for _ in unhandled_cust: await stat_dates.init() await stat_dates.setval('cust_row_id', await ar_cust.getval('row_id')) await stat_dates.setval('period_row_id', params['current_period']) if stat_dates.exists: raise AibError(head='Closing flag', body='Closing flag already set') await stat_dates.setval('statement_date', params['statement_date']) await stat_dates.setval('state', 'closing') await stat_dates.save() await ledg_per.setval('ledger_row_id', caller.context.mod_ledg_id[1]) await ledg_per.setval('period_row_id', params['current_period']) if await ledg_per.getval('state') != 'open': raise AibError(head='Closing flag', body='Closing flag already set') await ledg_per.setval('statement_date', params['statement_date']) await ledg_per.setval('state', 'closing') await ledg_per.save()
async def dump_tristates(caller, xml): # called from dbcols_setup before_save db_cols = caller.data_objects['db_cols'] var = caller.data_objects['var'] if await var.getval('allow_amend') == 'false': allow_amend = False elif await var.getval('allow_amend') == 'true': allow_amend = True else: amend = caller.data_objects['amend'] if await amend.getval('param') is None: raise AibError(head='Allow amend', body='Parameters required') allow_amend = [ await amend.getval('param'), await amend.getval('test'), { 'False': False, 'True': True, 'None': None }[await amend.getval('value')] ] await db_cols.setval('allow_amend', allow_amend) if await var.getval('calculated') == 'false': calculated = False elif await var.getval('calculated') == 'true': calculated = True else: calc = caller.data_objects['calc'] if await calc.getval('name') is None: raise AibError(head='Calculated', body='Parameters required') calculated = [ f'{await calc.getval("type")}.{await calc.getval("name")}', await calc.getval('test'), { 'False': False, 'True': True, 'None': None }[await calc.getval('value')] ] await db_cols.setval('calculated', calculated)
async def setup_form(form_name): xml = open('{}/{}.xml'.format(form_path, form_name)).read() await form_defn.init() await form_defn.setval('form_name', form_name) xml = xml.replace('`', '"').replace('<<', '<').replace( '>>', '>').replace('&&', '&') try: form_xml = etree.fromstring(xml, parser=parser) except (etree.XMLSyntaxError, ValueError, TypeError) as e: raise AibError(head=form_name, body=e.args[0]) await form_defn.setval('title', form_xml.get('title')) await form_defn.setval('form_xml', form_xml) await form_defn.save()
async def assign(caller, xml): source = xml.get('src') target = xml.get('tgt') format = xml.get('format') #------------------------------- # source could be an expression! #------------------------------- if format: """ <source> <format>{0} {1}</format> <arg>dir_users.first_name</arg> <arg>dir_users.surname</arg> </source> <target>var.full_name</target> """ # print('formatting') format_string = format.text format_args = [] for arg in source.arg: if '.' in arg.text: arg_objname, arg_colname = arg.text.split('.') arg_record = caller.data_objects[arg_objname] arg_field = await arg_record.getfld(arg_colname) format_arg = await arg_field.getval() else: raise AibError(head='Error', body='Unknown format argument {}'.format( arg.text)) format_args.append(format_arg) value_to_assign = format_string.format(*format_args) else: value_to_assign = await get_val(caller, source) # target can be objname.colname or objname.colname.keyname if data_type is a JSON dict target_objname, target_colname = target.split('.', maxsplit=1) if target_objname == '_ctx': setattr(caller.context, target_colname, value_to_assign) else: target_obj = caller.data_objects[target_objname] if '.' in target_colname: target_colname, target_key = target_colname.split('.') target_fld = await target_obj.getfld(target_colname) assert target_fld.col_defn.data_type == 'JSON' target_dict = await target_fld.getval() target_dict[target_key] = value_to_assign await target_fld.setval(target_dict) else: await target_obj.setval(target_colname, value_to_assign)
async def on_req_insert_node(self, args): parent_id, seq, node_type = args if not parent_id: raise AibError(head='Error', body='Cannot create new root') self.node_inserted = True self.insert_params = {'parent_id': parent_id, 'seq': seq} if self.levels: await self.db_obj.init(display=False, init_vals={'row_id': parent_id}) self.insert_params['level'] = await self.db_obj.getval('level') + 1 await self.db_obj.init() self.session.responder.send_insert_node(self.ref, parent_id, seq, -1) if self.tree_frame is not None: await self.tree_frame.restart_frame()
async def setup_process(process_id): xml = open('{}/{}.xml'.format(proc_path, process_id)).read() await proc_defn.init() await proc_defn.setval('process_id', process_id) xml = xml.replace('`', '"').replace('<<', '<').replace( '>>', '>').replace('&&', '&') try: proc_xml = etree.fromstring(xml, parser=parser) schema.assertValid(proc_xml.find(S + 'definitions')) except (etree.XMLSyntaxError, ValueError, TypeError) as e: raise AibError(head=process_id, body=e.args[0]) await proc_defn.setval('descr', proc_xml.get('descr')) await proc_defn.setval('proc_xml', proc_xml) await proc_defn.save()
async def get_val(caller, value): if value.startswith('('): # expression # for now assume a simple expression - # (lft [spc] op [spc] rgt) # e.g. (item_row_id>balance_cust + alloc_cust) lft, op, rgt = value[1:-1].split(' ') lft = await get_val(caller, lft) rgt = await get_val(caller, rgt) op = getattr(operator, { '+': 'add', '-': 'sub', '*': 'mul', '/': 'truediv' }[op]) if lft is None or rgt is None: return None else: return op(lft, rgt) if '.' in value: obj_name, col_name = value.split('.') if obj_name == '_ctx': if col_name == 'ledger_row_id': return getattr(caller.context, 'mod_ledg_id')[1] elif col_name == 'current_period': ledger_periods = await db.cache.get_ledger_periods( caller.company, *caller.context.mod_ledg_id) return ledger_periods.current_period else: return getattr(caller.context, col_name) else: if obj_name == '_param': db_obj = await db.cache.get_adm_params(caller.company) elif obj_name == '_ledger': module_row_id, ledger_row_id = caller.context.mod_ledg_id db_obj = await db.cache.get_ledger_params( caller.company, module_row_id, ledger_row_id) else: db_obj = caller.data_objects[obj_name] return await db_obj.getval(col_name) if value.startswith("'"): return value[1:-1] if value == '$True': return True if value == '$False': return False if value == '$None': return None if value.isdigit(): return int(value) raise AibError(head='Get value', body='Unknown value "{}"'.format(value))
async def set_per_closing_flag(caller, params): print('set_closing_flag') if 'ar_ledg_per' not in caller.context.data_objects: caller.context.data_objects[ 'ar_ledg_per'] = await db.objects.get_db_object( caller.context, caller.company, 'ar_ledger_periods') ledg_per = caller.context.data_objects['ar_ledg_per'] await ledg_per.setval('ledger_row_id', caller.context.mod_ledg_id[1]) await ledg_per.setval('period_row_id', params['current_period']) if await ledg_per.getval('state') not in ('current', 'open'): raise AibError(head='Closing flag', body='Period is not open') await ledg_per.setval('state', 'closing') await ledg_per.save()
async def handle_single_cust(): cust_row_id = params['cust_row_id'] if 'ar_stat_dates' not in caller.context.data_objects: caller.context.data_objects[ 'ar_stat_dates'] = await db.objects.get_db_object( caller.context, caller.company, 'ar_stat_dates') stat_dates = caller.context.data_objects['ar_stat_dates'] await stat_dates.setval('cust_row_id', cust_row_id) await stat_dates.setval('period_row_id', params['current_period']) if stat_dates.exists: raise AibError(head='Closing flag', body='Closing flag already set') await stat_dates.setval('statement_date', params['statement_date']) await stat_dates.setval('state', 'closing') await stat_dates.save()
async def handle_all_cust(): if 'ar_ledg_per' not in caller.context.data_objects: caller.context.data_objects[ 'ar_ledg_per'] = await db.objects.get_db_object( caller.context, caller.company, 'ar_ledger_periods') ledg_per = caller.context.data_objects['ar_ledg_per'] await ledg_per.setval('ledger_row_id', caller.context.mod_ledg_id[1]) await ledg_per.setval('period_row_id', params['current_period']) if await ledg_per.getval('statement_state') != 'open': raise AibError(head='Closing flag', body='Statement period is not open') await ledg_per.setval('statement_state', 'closing') process_row_id = await caller.manager.process.root.bpm_detail.getval( 'header_row_id') await ledg_per.setval('stmnt_process_id', process_row_id) await ledg_per.save()
async def get_form_title(company, form_name): with await title_lock: if '.' in form_name: company, form_name = form_name.split('.') async with db_session.get_connection() as db_mem_conn: conn = db_mem_conn.db sql = (f"SELECT title FROM {company}.sys_form_defns " f"WHERE form_name = {conn.constants.param_style}") params = (form_name, ) cur = await conn.exec_sql(sql, params) try: title, = await cur.__anext__() except StopAsyncIteration: # no rows selected raise AibError( head='Error', body=f'Form {company}.{form_name} does not exist') return title
async def after_party_id(caller, xml): # called from setup_party after var.party_id var = caller.data_objects['var'] var_id = await var.getval('party_id') party = caller.data_objects['party'] await party.setval('party_id', var_id) if var_id == '<new>': return if party.exists: party_id = await party.getval('party_id') await var.setval('party_id', party_id) # to change 'a001' to 'A001' else: param_obj = await db.cache.get_adm_params(var.company) if await param_obj.getval('auto_party_id') is not None: raise AibError(head='Error', body='Does not exist')
async def init_xml(caller, xml): # called from setup_process after process_id if process does not exist proc = caller.data_objects['proc'] process_id = await proc.getval('process_id') proc_xml = etree.Element('process_root') proc_xml.set('process_id', process_id) etree.SubElement(proc_xml, 'db_objects') etree.SubElement(proc_xml, 'mem_objects') etree.SubElement(proc_xml, 'input_params') etree.SubElement(proc_xml, 'output_params') S = "{http://www.omg.org/spec/BPMN/20100524/MODEL}" nsmap = {} nsmap['semantic'] = 'http://www.omg.org/spec/BPMN/20100524/MODEL' nsmap['bpmndi'] = 'http://www.omg.org/spec/BPMN/20100524/DI' nsmap['di'] = 'http://www.omg.org/spec/DD/20100524/DI' nsmap['dc'] = 'http://www.omg.org/spec/DD/20100524/DC' nsmap['dbobj'] = 'http://www.accinabox.org/bpmn/dbobj_definitions' nsmap['memobj'] = 'http://www.accinabox.org/bpmn/memobj_definitions' bpmn_xml = etree.SubElement(proc_xml, S + 'definitions', nsmap=nsmap) bpmn_xml.set('id', f'{process_id}_0') bpmn_xml.set('targetNamespace', 'http://www.accinabox.org/bpmn') proc_elem = etree.SubElement(bpmn_xml, f"{{{bpmn_xml.nsmap['semantic']}}}process") proc_elem.set('id', process_id + '_1') proc_elem.set('isExecutable', "true") diag_elem = etree.SubElement(bpmn_xml, f"{{{bpmn_xml.nsmap['bpmndi']}}}BPMNDiagram") diag_elem.set('id', process_id + '_2') # diag_elem.set('name', ???) # diag_elem.set('resolution', ???) plane_elem = etree.SubElement(diag_elem, f"{{{bpmn_xml.nsmap['bpmndi']}}}BPMNPlane") plane_elem.set('bpmnElement', proc_elem.get('id')) try: etree.fromstring(etree.tostring(bpmn_xml), parser=xsd_parser) except (etree.XMLSyntaxError, ValueError, TypeError) as e: raise AibError(head='XmlError', body=e.args[0]) await proc.setval('proc_xml', proc_xml) await load_proc_xml(caller, xml)
async def _fetch_row(self, row_no): # overridden in db.cur_sqlite3 # i.e. set up self.row_data if self.debug: print('fetch row', row_no, 'cursor_pos =', self.cursor_pos) if row_no in self.new_rows: self.row_data = self.new_rows[row_no] if self.debug: print(self.row_data) return if row_no >= self.num_rows: print('should not get here - {},{}'.format(row_no, self.num_rows)) self.debugger() raise AibError(head=self.db_obj.table_name, body='Should not get here - {}, {}'.format( row_no, self.num_rows)) row_no = self._grid_to_cursor(row_no) diff = row_no - self.cursor_pos if diff == 0: if self.debug: print('fetch relative 0 from _aib') cur = await self.conn.exec_sql('fetch relative 0 from _aib') elif diff == 1: if self.debug: print('fetch next from _aib') cur = await self.conn.exec_sql('fetch next from _aib') elif diff == -1: if self.debug: print('fetch prior from _aib') cur = await self.conn.exec_sql('fetch prior from _aib') else: if self.debug: print('fetch absolute {} from _aib'.format(row_no + 1)) # python is 0-based, cursor is 1-based cur = await self.conn.exec_sql( 'fetch absolute {} from _aib'.format(row_no + 1)) self.cursor_pos = row_no # self.row_data = await cur.__anext__() row = await cur.__anext__() self.row_data = [ await self.db_obj.get_val_from_sql(col_name, dat) for col_name, dat in zip(self.col_names, row) ] if self.debug: print('POS =', self.cursor_pos, ', DATA =', self.row_data)
async def error(ctx, fld, value, xml): body = xml.get('body') if body is not None: if '$value' in body: body = body.replace('$value', str(value)) if '{' in body: pos1 = body.index('{') pos2 = body.index('}') sub_col = body[pos1 + 1:pos2] if '.' in sub_col: sub_tbl, sub_col = sub_col.split('.') sub_dbobj = ctx.data_objects[sub_tbl] else: sub_dbobj = fld.db_obj sub_fld = await sub_dbobj.getfld(sub_col) body = body[:pos1] + await sub_fld.getval() + body[pos2 + 1:] raise AibError(head=xml.get('head'), body=body)
async def setup_inv_alloc(db_obj, conn, return_vals): # called as split_src func from sls_isls_subinv.upd_on_save() # return values - cost_whouse, cost_local tot_to_allocate = await db_obj.getval('qty') if 'fifo' not in db_obj.context.data_objects: db_obj.context.data_objects['fifo'] = await db.objects.get_db_object( db_obj.context, db_obj.company, 'in_wh_prod_fifo') fifo = db_obj.context.data_objects['fifo'] cols_to_select = [ 'row_id', 'unalloc_qty', 'unalloc_whouse', 'unalloc_local' ] where = [ ('WHERE', '', 'wh_prod_row_id', '=', await db_obj.getval('wh_prod_row_id'), ''), ('AND', '', 'unalloc_qty', '>', 0, ''), ] order = [('tran_date', False), ('row_id', False)] async for row_id, unalloc_qty, unalloc_wh, unalloc_loc in await conn.full_select( fifo, cols_to_select, where=where, order=order): if tot_to_allocate > unalloc_qty: qty_allocated = unalloc_qty cost_wh = unalloc_wh cost_loc = unalloc_loc else: qty_allocated = tot_to_allocate cost_wh = unalloc_wh / unalloc_qty * qty_allocated cost_loc = unalloc_loc / unalloc_qty * qty_allocated if qty_allocated: # can it ever be zero ?? yield ( row_id, qty_allocated, cost_wh, cost_loc, ) tot_to_allocate -= qty_allocated return_vals[0] += cost_wh return_vals[1] += cost_loc if not tot_to_allocate: break # fully allocated if tot_to_allocate: # should never get here raise AibError(head='Error', body='Insufficient stock')
async def get_dflt_date(caller, obj, xml): # called as form_dflt from various 'tran_date' fields prev_date = await obj.fld.get_prev() if prev_date is not None: return prev_date db_obj = obj.fld.db_obj adm_periods = await db.cache.get_adm_periods(db_obj.company) ledger_periods = await db.cache.get_ledger_periods( caller.company, *caller.context.mod_ledg_id) if ledger_periods == {}: raise AibError(head=obj.fld.col_defn.short_descr, body='Ledger periods not set up') curr_closing_date = adm_periods[ledger_periods.current_period].closing_date today = dt.today() if today < curr_closing_date: return today else: return curr_closing_date
async def get_mod_ledg_id(company, module_id, ledger_id): search_key = (module_id, ledger_id) with await mod_ledg_lock: if company not in mod_ledg_ids: mod_ledg_ids[company] = {} if search_key not in mod_ledg_ids[company]: module_row_id = await get_mod_id(company, module_id) async with db_session.get_connection() as db_mem_conn: conn = db_mem_conn.db sql = ( f"SELECT row_id, ledger_id FROM {company}.{module_id}_ledger_params " "WHERE deleted_id = 0") async for ledger_row_id, ledger_id in await conn.exec_sql(sql): mod_ledg_ids[company][ module_id, ledger_id] = module_row_id, ledger_row_id try: return mod_ledg_ids[company][search_key] except KeyError: raise AibError(head='Module/ledger_id', body='"{}.{}" not found'.format(*search_key))