class SaleOrder(Model): _inherit = 'sale.order' def _amount_all(self, cursor, user, ids, field_name, arg, context=None): '''Calculate the markup rate based on sums''' if context is None: context = {} res = {} res = super(SaleOrder, self)._amount_all(cursor, user, ids, field_name, arg, context) for sale_order in self.browse(cursor, user, ids): cost_sum = 0.0 sale_sum = 0.0 for line in sale_order.order_line: cost_sum += line.cost_price sale_sum += line.price_unit * (100 - line.discount) / 100.0 res[sale_order.id]['markup_rate'] = sale_sum and ( sale_sum - cost_sum) / sale_sum * 100 or 0.0 return res def _get_order(self, cr, uid, ids, context=None): if context is None: context = {} result = set() for line in self.pool.get('sale.order.line').browse(cr, uid, ids, context=context): result.add(line.order_id.id) return list(result) _store_sums = { 'sale.order': (lambda self, cr, uid, ids, c={}: ids, ['order_line'], 10), 'sale.order.line': (_get_order, [ 'price_unit', 'tax_id', 'discount', 'product_uom_qty', 'product_id', 'commercial_margin', 'markup_rate' ], 10) } _columns = { 'markup_rate': fields.function(_amount_all, method=True, string='Markup Rate', digits_compute=dp.get_precision('Sale Price'), store=_store_sums, multi='sums') }
class product_product(Model): _inherit = "product.product" def _compute_configurable_level(self, cursor, uid, pids, field_name, args, context=None): """We compute a custom stock level""" # we do not override _product_available once agin to avoid MRO troubles conf_obj = self.pool.get('stock.level.configuration') prod_obj = self.pool.get('product.product') conf_list = [] conf_ids = conf_obj.search(cursor, uid, []) for conf in conf_obj.browse(cursor, uid, conf_ids): conf_list.append( (conf.stock_location_id.id, conf.product_field.name)) if not isinstance(pids, list): pids = [pids] res = dict.fromkeys(pids, 0.0) for conf in conf_list: local_context = context.copy() local_context['location'] = [conf[0]] interm = prod_obj._product_available(cursor, uid, pids, field_names=[conf[1]], arg=False, context=local_context) for key, val in interm.items(): res.setdefault( key, 0.0) # this should not be usefull but we never know res[key] += val.get(conf[1], 0.0) return res _columns = { 'configurable_stock_level': fields.function(_compute_configurable_level, type='float', digits_compute=dp.get_precision('Product UoM'), string='Custom level') }
class AccountInvoice(Model): """Inherit account.invoice in order to add bvr printing functionnalites. BVR is a Swiss payment vector""" _inherit = "account.invoice" _compile_get_ref = re.compile('[^0-9]') def _get_reference_type(self, cursor, user, context=None): """Function use by the function field reference_type in order to initalise available BVR Reference Types""" res = super(AccountInvoice, self)._get_reference_type(cursor, user, context=context) res.append(('bvr', 'BVR')) return res def _compute_full_bvr_name(self, cursor, uid, ids, field_names, arg, context=None): res = {} move_line_obj = self.pool.get('account.move.line') account_obj = self.pool.get('account.account') tier_account_id = account_obj.search( cursor, uid, [('type', 'in', ['receivable', 'payable'])]) for inv in self.browse(cursor, uid, ids, context=context): move_lines = move_line_obj.search( cursor, uid, [('move_id', '=', inv.move_id.id), ('account_id', 'in', tier_account_id)]) if move_lines: if len(move_lines) == 1: res[inv.id] = self._space(inv.get_bvr_ref()) else: refs = [] for move_line in move_line_obj.browse(cursor, uid, move_lines, context=context): refs.append(self._space(move_line.get_bvr_ref())) res[inv.id] = ' ; '.join(refs) return res _columns = { ### BVR reference type BVR or FREE 'reference_type': fields.selection(_get_reference_type, 'Reference Type', required=True), ### Partner bank link between bank and partner id 'partner_bank_id': fields.many2one( 'res.partner.bank', 'Bank Account', help= 'The partner bank account to pay\nKeep empty to use the default'), 'bvr_reference': fields.function(_compute_full_bvr_name, type="char", size=512, string="BVR REF.", store=True, readonly=True) } def get_bvr_ref(self, cursor, uid, inv_id, context=None): """Retrieve ESR/BVR reference form invoice in order to print it""" res = '' if isinstance(inv_id, list): inv_id = inv_id[0] inv = self.browse(cursor, uid, inv_id, context=context) ## We check if the type is bvr, if not we return false if inv.partner_bank_id.state != 'bvr': return '' ## if inv.partner_bank_id.bvr_adherent_num: res = inv.partner_bank_id.bvr_adherent_num invoice_number = '' if inv.number: invoice_number = self._compile_get_ref.sub('', inv.number) return mod10r(res + invoice_number.rjust(26 - len(res), '0')) def _space(self, nbr, nbrspc=5): """Spaces * 5. Example: self._space('123456789012345') '12 34567 89012 345' """ return ''.join([' '[(i - 2) % nbrspc:] + c for i, c in enumerate(nbr)]) def _update_ref_on_account_analytic_line(self, cr, uid, ref, move_id, context=None): cr.execute( 'UPDATE account_analytic_line SET ref=%s' ' FROM account_move_line ' ' WHERE account_move_line.move_id = %s ' ' AND account_analytic_line.move_id = account_move_line.id', (ref, move_id)) return True def action_number(self, cr, uid, ids, context=None): res = super(AccountInvoice, self).action_number(cr, uid, ids, context=context) move_line_obj = self.pool.get('account.move.line') account_obj = self.pool.get('account.account') tier_account_id = account_obj.search( cr, uid, [('type', 'in', ['receivable', 'payable'])]) for inv in self.browse(cr, uid, ids, context=context): if inv.type != 'out_invoice' and inv.partner_bank_id.state != 'bvr': continue move_lines = move_line_obj.search( cr, uid, [('move_id', '=', inv.move_id.id), ('account_id', 'in', tier_account_id)]) # We keep this branch for compatibility with single BVR report. # This should be cleaned when porting to V8 if move_lines: if len(move_lines) == 1: ref = inv.get_bvr_ref() move_id = inv.move_id if move_id: cr.execute( 'UPDATE account_move_line SET transaction_ref=%s' ' WHERE move_id=%s', (ref, move_id.id)) self._update_ref_on_account_analytic_line( cr, uid, ref, move_id.id) else: for move_line in move_line_obj.browse(cr, uid, move_lines, context=context): ref = move_line.get_bvr_ref() if ref: cr.execute( 'UPDATE account_move_line SET transaction_ref=%s' ' WHERE id=%s', (ref, move_line.id)) self._update_ref_on_account_analytic_line( cr, uid, ref, move_line.move_id.id) return res def copy(self, cursor, uid, inv_id, default=None, context=None): default = default or {} default.update({'reference': False}) return super(AccountInvoice, self).copy(cursor, uid, inv_id, default, context)
class AccountInvoice(Model): """Inherit account.invoice in order to add bvr printing functionnalites. BVR is a Swiss payment vector""" _inherit = "account.invoice" _compile_get_ref = re.compile('[^0-9]') def _get_reference_type(self, cr, user, context=None): """Function used by the function field 'reference_type' in order to initalise available BVR Reference Types """ res = super(AccountInvoice, self)._get_reference_type(cr, user, context=context) res.append(('bvr', 'BVR')) return res def _compute_full_bvr_name(self, cr, uid, ids, field_names, arg, context=None): res = {} move_line_obj = self.pool.get('account.move.line') account_obj = self.pool.get('account.account') tier_account_id = account_obj.search( cr, uid, [('type', 'in', ['receivable', 'payable'])], context=context) for inv in self.browse(cr, uid, ids, context=context): move_lines = move_line_obj.search( cr, uid, [('move_id', '=', inv.move_id.id), ('account_id', 'in', tier_account_id)], context=context) if move_lines: refs = [] for move_line in move_line_obj.browse(cr, uid, move_lines, context=context): refs.append(AccountInvoice._space(move_line.get_bvr_ref())) res[inv.id] = ' ; '.join(refs) return res _columns = { # BVR reference type BVR or FREE 'reference_type': fields.selection(_get_reference_type, 'Reference Type', required=True), # Partner bank link between bank and partner id 'partner_bank_id': fields.many2one('res.partner.bank', 'Bank Account', help='The partner bank account to pay\n' 'Keep empty to use the default'), 'bvr_reference': fields.function(_compute_full_bvr_name, type="char", size=512, string="BVR REF.", store=True, readonly=True) } @staticmethod def _space(nbr, nbrspc=5): """Spaces * 5. Example: AccountInvoice._space('123456789012345') '12 34567 89012 345' """ return ''.join([' '[(i - 2) % nbrspc:] + c for i, c in enumerate(nbr)]) def _update_ref_on_account_analytic_line(self, cr, uid, ref, move_id, context=None): """Propagate reference on analytic line""" cr.execute( 'UPDATE account_analytic_line SET ref=%s' ' FROM account_move_line ' ' WHERE account_move_line.move_id = %s ' ' AND account_analytic_line.move_id = account_move_line.id', (ref, move_id)) return True def _action_bvr_number_move_line(self, cr, uid, invoice, move_line, ref, context=None): """Propagate reference on move lines and analytic lines""" if not ref: return cr.execute( 'UPDATE account_move_line SET transaction_ref=%s' ' WHERE id=%s', (ref, move_line.id)) self._update_ref_on_account_analytic_line(cr, uid, ref, move_line.move_id.id) def action_number(self, cr, uid, ids, context=None): """ Copy the BVR/ESR reference in the transaction_ref of move lines. For customers invoices: the BVR reference is computed using ``get_bvr_ref()`` on the invoice or move lines. For suppliers invoices: the BVR reference is stored in the reference field of the invoice. """ res = super(AccountInvoice, self).action_number(cr, uid, ids, context=context) move_line_obj = self.pool.get('account.move.line') for inv in self.browse(cr, uid, ids, context=context): move_line_ids = move_line_obj.search( cr, uid, [('move_id', '=', inv.move_id.id), ('account_id', '=', inv.account_id.id)], context=context) if not move_line_ids: continue move_lines = move_line_obj.browse(cr, uid, move_line_ids, context=context) for move_line in move_lines: if inv.type in ('out_invoice', 'out_refund'): ref = move_line.get_bvr_ref() elif inv.reference_type == 'bvr' and inv.reference: ref = inv.reference else: ref = False self._action_bvr_number_move_line(cr, uid, inv, move_line, ref, context=context) return res def copy(self, cr, uid, inv_id, default=None, context=None): default = default or {} default.update({'reference': False}) return super(AccountInvoice, self).copy(cr, uid, inv_id, default, context)
class ResPartner(Model): """Adds lastname and firstname, name become a stored function field""" _inherit = 'res.partner' def init(self, cursor): cursor.execute( 'SELECT id FROM res_partner WHERE lastname IS NOT NULL Limit 1') if not cursor.fetchone(): cursor.execute( 'UPDATE res_partner set lastname = name WHERE name IS NOT NULL' ) # Create Sql constraint if table is not empty cursor.execute('SELECT id FROM res_partner Limit 1') if cursor.fetchone(): cursor.execute( 'ALTER TABLE res_partner ALTER COLUMN lastname SET NOT NULL' ) def _prepare_name_custom(self, cursor, uid, partner, context=None): """ This function is designed to be inherited in a custom module """ names = (partner.lastname, partner.firstname) fullname = " ".join([s for s in names if s]) return fullname def _compute_name_custom(self, cursor, uid, ids, fname, arg, context=None): res = {} for partner in self.browse(cursor, uid, ids, context=context): res[partner.id] = self._prepare_name_custom(cursor, uid, partner, context=context) return res def _write_name(self, cursor, uid, partner_id, field_name, field_value, arg, context=None): """ Try to reverse the effect of _compute_name_custom: * if the partner is not a company and the firstname does not change in the new name then firstname remains untouched and lastname is updated accordingly * otherwise lastname=new name and firstname=False In addition an heuristic avoids to keep a firstname without a non-blank lastname """ field_value = field_value and not field_value.isspace( ) and field_value or False vals = {'lastname': field_value, 'firstname': False} if field_value: flds = self.read(cursor, uid, [partner_id], ['firstname', 'is_company'], context=context)[0] if not flds['is_company']: to_check = ' %s' % flds['firstname'] if field_value.endswith(to_check): ln = field_value[:-len(to_check)].strip() if ln: vals['lastname'] = ln del (vals['firstname']) else: # If the lastname is deleted from the new name # then the firstname becomes the lastname vals['lastname'] = flds['firstname'] return self.write(cursor, uid, partner_id, vals, context=context) def copy_data(self, cr, uid, _id, default=None, context=None): """ Avoid to replicate the firstname into the name when duplicating a partner """ default = default or {} if not default.get('lastname'): default = default.copy() default['lastname'] = _('%s (copy)') % self.read( cr, uid, [_id], ['lastname'], context=context)[0]['lastname'] if default.get('name'): del (default['name']) return super(ResPartner, self).copy_data(cr, uid, _id, default, context=context) def create(self, cursor, uid, vals, context=None): """ To support data backward compatibility we have to keep this overwrite even if we use fnct_inv: otherwise we can't create entry because lastname is mandatory and module will not install if there is demo data """ to_use = vals if 'name' in vals: corr_vals = vals.copy() corr_vals['lastname'] = corr_vals['name'] del (corr_vals['name']) to_use = corr_vals return super(ResPartner, self).create(cursor, uid, to_use, context=context) _columns = { 'name': fields.function(_compute_name_custom, string="Name", type="char", store=True, select=True, readonly=True, fnct_inv=_write_name), 'firstname': fields.char("Firstname"), 'lastname': fields.char("Lastname", required=True) }