def _setup_inv_data(self, journal, invoicer, contracts): """ Inherit to add BVR ref and mandate """ inv_data = super()._setup_inv_data(journal, invoicer, contracts) ref = "" bank_modes = ( self.env["account.payment.mode"] .with_context(lang="en_US") .search(["|", ("name", "like", "LSV"), ("name", "like", "Postfinance")]) ) bank = self.env["res.partner.bank"] if self.bvr_reference: ref = self.bvr_reference bank = bank.search([("acc_number", "=", "01444437")]) elif self.payment_mode_id in bank_modes: seq = self.env["ir.sequence"] ref = mod10r(seq.next_by_code("contract.bvr.ref")) bank = self.payment_mode_id.fixed_journal_id.bank_account_id mandate = self.env["account.banking.mandate"].search( [("partner_id", "=", self.partner_id.id), ("state", "=", "valid")], limit=1 ) inv_data.update( {"reference": ref, "mandate_id": mandate.id, "partner_bank_id": bank.id, } ) return inv_data
def action_date_assign(self): """Method called when invoice is validated. - Add BVR Reference if payment mode is LSV and no reference is set. - Prevent validating invoices missing related contract. """ to_validate = self.filtered(lambda i: i.partner_id.state != 'active') if to_validate: raise UserError( _('Please verify the partner before validating the invoice.')) for invoice in self.filtered('payment_mode_id'): if 'LSV' in invoice.payment_mode_id.name \ and not invoice.reference: seq = self.env['ir.sequence'] ref = mod10r(seq.next_by_code('contract.bvr.ref')) invoice.write({'reference': ref}) for invl in invoice.invoice_line_ids: if not invl.contract_id and invl.product_id.categ_name in ( SPONSORSHIP_CATEGORY, GIFT_CATEGORY): raise UserError( _("Invoice %s for '%s' is missing a sponsorship.") % (str(invoice.id), invoice.partner_id.name)) return super(AccountInvoice, self).action_date_assign()
def generate_bvr_reference(self, contract, product): product = product.with_context(lang="en_US") ref = contract.gift_partner_id.ref bvr_reference = "0" * (9 + (7 - len(ref))) + ref commitment_number = str(contract.commitment_number) bvr_reference += "0" * (5 - len(commitment_number)) + commitment_number # Type of gift bvr_reference += str(GIFT_REF.index(product.default_code) + 1) bvr_reference += "0" * 4 if contract.payment_mode_id and "LSV" in contract.payment_mode_id.name: # Get company BVR adherent number user = self.env.user bank_obj = self.env["res.partner.bank"] company_bank = bank_obj.search( [ ("partner_id", "=", user.company_id.partner_id.id), ("l10n_ch_isr_subscription_chf", "!=", False), ("acc_type", "=", "iban"), ], limit=1, ) if company_bank: bvr_reference = company_bank.l10n_ch_isrb_id_number + bvr_reference[ 9:] if len(bvr_reference) == 26: return mod10r(bvr_reference) return False
def generate_bvr_reference(self, contract, product): product = product.with_context(lang='en_US') ref = getattr(contract, contract.send_gifts_to, contract.correspondant_id).ref bvr_reference = '0' * (9 + (7 - len(ref))) + ref commitment_number = str(contract.commitment_number) bvr_reference += '0' * (5 - len(commitment_number)) + commitment_number # Type of gift bvr_reference += str(GIFT_NAMES.index(product.name) + 1) bvr_reference += '0' * 4 if contract.payment_mode_id and 'LSV' in contract.payment_mode_id.name: # Get company BVR adherent number user = self.env.user bank_obj = self.env['res.partner.bank'] company_bank = bank_obj.search([('partner_id', '=', user.company_id.partner_id.id), ('bvr_adherent_num', '!=', False)]) if company_bank: bvr_reference = company_bank.bvr_adherent_num +\ bvr_reference[9:] if len(bvr_reference) == 26: return mod10r(bvr_reference) return False
def _setup_inv_data(self, journal, invoicer, contracts): """ Inherit to add BVR ref and mandate """ inv_data = super(ContractGroup, self)._setup_inv_data( journal, invoicer, contracts) ref = '' bank_modes = self.env['account.payment.mode'].with_context( lang='en_US').search( ['|', ('name', 'like', 'LSV'), ('name', 'like', 'Postfinance')]) bank = self.env['res.partner.bank'] if self.bvr_reference: ref = self.bvr_reference bank = bank.search([('acc_number', '=', '01444437')]) elif self.payment_mode_id in bank_modes: seq = self.env['ir.sequence'] ref = mod10r(seq.next_by_code('contract.bvr.ref')) bank = self.payment_mode_id.fixed_journal_id.bank_account_id mandate = self.env['account.banking.mandate'].search([ ('partner_id', '=', self.partner_id.id), ('state', '=', 'valid') ], limit=1) inv_data.update({ 'reference': ref, 'mandate_id': mandate.id, 'partner_bank_id': bank.id, }) return inv_data
def _create_invoice_from_mv_lines(self, mv_line_dicts, invoice=None): # Generate a unique bvr_reference if self.ref and len(self.ref) == 27: ref = self.ref elif self.ref and len(self.ref) > 27: ref = mod10r(self.ref[:26]) else: ref = mod10r((self.date.replace('-', '') + str( self.statement_id.id) + str(self.id)).ljust(26, '0')) if invoice: invoice.action_invoice_cancel() invoice.action_invoice_draft() invoice.env.invalidate_all() invoice.write({'origin': self.statement_id.name}) else: # Lookup for an existing open invoice matching the criterias invoices = self._find_open_invoice(mv_line_dicts) if invoices: # Get the bvr reference of the invoice or set it invoice = invoices[0] invoice.write({'origin': self.statement_id.name}) if invoice.reference and not self.ref: ref = invoice.reference else: invoice.write({'reference': ref}) self.write({ 'ref': ref, 'invoice_id': invoice.id}) return True # Setup a new invoice if no existing invoice is found inv_data = self._get_invoice_data(ref, mv_line_dicts) invoice = self.env['account.invoice'].create(inv_data) for mv_line_dict in mv_line_dicts: inv_line_data = self._get_invoice_line_data(mv_line_dict, invoice) self.env['account.invoice.line'].create(inv_line_data) invoice.action_invoice_open() self.ref = ref # Update move_lines data counterpart = invoice.move_id.line_ids.filtered( lambda ml: ml.debit > 0) return counterpart
def _create_invoice_from_mv_lines(self, mv_line_dicts, invoice=None): # Generate a unique bvr_reference if self.ref and len(self.ref) == 27: ref = self.ref elif self.ref and len(self.ref) > 27: ref = mod10r(self.ref[:26]) else: ref = mod10r( str(self.date).replace("-", "") + str(self.statement_id.id) + str(self.id)).ljust(26, "0") if invoice: invoice.action_invoice_cancel() invoice.action_invoice_draft() invoice.env.clear() invoice.write({"origin": self.statement_id.name}) else: # Lookup for an existing open invoice matching the criterias invoices = self._find_open_invoice(mv_line_dicts) if invoices: # Get the bvr reference of the invoice or set it invoice = invoices[0] invoice.write({"origin": self.statement_id.name}) if invoice.reference and not self.ref: ref = invoice.reference else: invoice.write({"reference": ref}) self.write({"ref": ref, "invoice_id": invoice.id}) return True # Setup a new invoice if no existing invoice is found inv_data = self._get_invoice_data(ref, mv_line_dicts) invoice = self.env["account.invoice"].create(inv_data) for mv_line_dict in mv_line_dicts: inv_line_data = self._get_invoice_line_data(mv_line_dict, invoice) self.env["account.invoice.line"].create(inv_line_data) invoice.action_invoice_open() self.ref = ref # Update move_lines data counterpart = invoice.move_id.line_ids.filtered( lambda ml: ml.debit > 0) return counterpart
def on_change_bvr_ref(self): """ Test the validity of a reference number. """ bvr_reference = self.bvr_reference is_valid = bvr_reference and bvr_reference.isdigit() if is_valid and len(bvr_reference) == 26: bvr_reference = mod10r(bvr_reference) elif is_valid and len(bvr_reference) == 27: valid_ref = mod10r(bvr_reference[:-1]) is_valid = (valid_ref == bvr_reference) else: is_valid = False if is_valid: self.bvr_reference = bvr_reference elif bvr_reference: raise UserError( _('The reference of the partner has not been set, or is in ' 'wrong format. Please make sure to enter a valid BVR ' 'reference for the contract.'))
def _is_isr_reference(self): """ Function to validate a ISR reference like : 0100054150009>132000000000000000000000014+ 1300132412> The validation is based on l10n_ch """ if not self.reference: raise exceptions.ValidationError(_('ISR Reference is required')) # In this case # <010001000060190> 052550152684006+ 43435> # the reference 052550152684006 do not match modulo 10 # if (mod10r(self.reference[:-1]) != self.reference and len(self.reference) == 15): return True # if mod10r(self.reference[:-1]) != self.reference: raise exceptions.ValidationError( _('Invalid ISR Number (wrong checksum).'))
def is_bvr_ref(ref): if not ref: return False # Empty is not valid clean_ref = ref.replace(' ', '') if not clean_ref.isdigit() or len(clean_ref) > 27: return False clean_ref = clean_ref.rjust(27, '0') # Add zeros to the left if not clean_ref == mod10r(clean_ref[0:26]): return False return True
def validate_global_context_dict(self): """Validate BVR record values""" super(RecordGt826, self).validate_global_context_dict() if not self.global_values['reference']: raise exceptions.UserError( _('You must provide a BVR reference' 'number \n for the line: %s') % self.pline.name ) ref = self.global_values['reference'].replace(' ', '') self.global_values['reference'] = ref if self.is_9_pos_adherent: if len(ref) > 27: raise exceptions.UserError( _('BVR reference number is not valid \n' 'for the line: %s. \n' 'Reference is too long.') % self.pline.name ) # do a mod10 check if mod10r(ref[:-1]) != ref: raise exceptions.UserError( _('BVR reference number is not valid \n' 'for the line: %s. \n' 'Mod10 check failed') % self.pline.name ) # fill reference with 0 self.global_values['reference'] = ref.rjust(27, '0') else: # reference of BVR adherent with 5 positions number # have 15 positions references if len(ref) > 15: raise exceptions.UserError( _('BVR reference number is not valid \n' 'for the line: %s. \n Reference is too long ' 'for this type of beneficiary.') % self.pline.name ) # complete 15 first digit with 0 on left and complete 27 digits # with trailing spaces # exemple: 123456 becomes 00000000012345____________ adjust = ref.rjust(15, '0').ljust(27, ' ') self.global_values['reference'] = adjust if not self.global_values['partner_bvr']: raise exceptions.UserError( _('You must provide a BVR number\n' 'for the bank account: %s' 'on line: %s') % ( self.pline.partner_bank_id.get_account_number(), self.pline.name) )
def _update_invoice_lines(self, invoices): """ Update bvr_reference of invoices """ super(RecurringContracts, self)._update_invoice_lines(invoices) for contract in self: ref = False bank_modes = self.env['account.payment.mode'].with_context( lang='en_US').search( ['|', ('name', 'like', 'LSV'), ('name', 'like', 'Postfinance')]) if contract.group_id.bvr_reference: ref = contract.group_id.bvr_reference elif contract.payment_mode_id in bank_modes: seq = self.env['ir.sequence'] ref = mod10r(seq.next_by_code('contract.bvr.ref')) invoices.write({'reference': ref})
def _is_isr_reference(self): """Check if the communication is a valid ISR reference e.g. 210000000003139471430009017 21 00000 00003 13947 14300 09017 This is used to determine SEPA local instrument """ if not self.reference: return False if re.match(r'^(\d{27}|\d{2}( \d{5}){5})$', self.reference): ref = self.reference.replace(' ', '') return ref == mod10r(ref[:-1]) return False
def _update_invoice_lines(self, invoices): """ Update bvr_reference of invoices """ super(RecurringContracts, self)._update_invoice_lines(invoices) for contract in self: ref = False bank_modes = self.env['account.payment.mode'].with_context( lang='en_US').search([ '|', ('name', 'like', 'LSV'), ('name', 'like', 'Postfinance') ]) if contract.group_id.bvr_reference: ref = contract.group_id.bvr_reference elif contract.payment_mode_id in bank_modes: seq = self.env['ir.sequence'] ref = mod10r(seq.next_by_code('contract.bvr.ref')) invoices.write({'reference': ref})
def _update_invoice_lines(self, invoices): """ Update bvr_reference of invoices """ success = super()._update_invoice_lines(invoices) for contract in self: ref = False bank_modes = (self.env["account.payment.mode"].with_context( lang="en_US").search([ "|", ("name", "like", "LSV"), ("name", "like", "Postfinance") ])) if contract.group_id.bvr_reference: ref = contract.group_id.bvr_reference elif contract.payment_mode_id in bank_modes: seq = self.env["ir.sequence"] ref = mod10r(seq.next_by_code("contract.bvr.ref")) invoices.write({"reference": ref}) return success
def is_post_dd_ident_valid(self, dd_identifier): """ Check if given Postfinance DD Identifier is valid """ if not isinstance(dd_identifier, basestring): return False try: dd_identifier.decode('ascii') except UnicodeDecodeError: raise exceptions.ValidationError( _('DD identifier should contain only ASCII caracters.') ) if not len(dd_identifier) == 6: return False if not dd_identifier == mod10r(dd_identifier[:5]): return False return True
def generate_bvr_reference(self, product): """ Generates a bvr reference for a donation to the fund given by the product. :param product: fund product with a fund_id :return: bvr reference for the partner """ self.ensure_one() if isinstance(product, int): product = self.env['product.product'].browse(product) ref = self.ref bvr_reference = '0' * (9 + (7 - len(ref))) + ref bvr_reference += '0' * 5 bvr_reference += '6' # Fund donation bvr_reference += '0' * (4 - len(product.fund_id)) + product.fund_id bvr_reference += '0' * 4 if len(bvr_reference) == 26: return mod10r(bvr_reference)
def _check_9_pos_postal_num(self, number): """ Predicate that checks if a postal number is in format xx-xxxxxx-x is correct, return true if it matches the pattern and if check sum mod10 is ok :param number: postal number to validate :returns: True if is it a 9 len postal account :rtype: bool """ pattern = r'^[0-9]{2}-[0-9]{1,6}-[0-9]$' if not re.search(pattern, number): return False nums = number.split('-') prefix = nums[0] num = nums[1].rjust(6, '0') checksum = nums[2] expected_checksum = mod10r(prefix + num)[-1] return expected_checksum == checksum
def action_date_assign(self): """Method called when invoice is validated. - Add BVR Reference if payment mode is LSV and no reference is set. - Prevent validating invoices missing related contract. """ for invoice in self.filtered('payment_mode_id'): if 'LSV' in invoice.payment_mode_id.name \ and not invoice.reference: seq = self.env['ir.sequence'] ref = mod10r(seq.next_by_code('contract.bvr.ref')) invoice.write({'reference': ref}) for invl in invoice.invoice_line_ids: if not invl.contract_id and invl.product_id.categ_name in ( SPONSORSHIP_CATEGORY, GIFT_CATEGORY): raise UserError( _("Invoice %s for '%s' is missing a sponsorship.") % (str(invoice.id), invoice.partner_id.name)) return super(AccountInvoice, self).action_date_assign()
def generate_bvr_reference(self, partner): """ Generates a BVR reference for the product. :param partner: :return: string: the BVR reference """ self.ensure_one() ref = partner.ref bvr_reference = '0' * (9 + (7 - len(ref))) + ref commitment_number = '0' bvr_reference += '0' * (5 - len(commitment_number)) + commitment_number # Type for Funds => 6 bvr_reference += '6' # Fund id fund_id = str(self.fund_id) bvr_reference += '0' * (4 - len(fund_id)) + fund_id if len(bvr_reference) == 26: return self.env['l10n_ch.payment_slip']._space(mod10r( bvr_reference).lstrip('0'))
def validate_l10n_ch_postal(postal_acc_number): """Check if the string postal_acc_number is a valid postal account number, i.e. it only contains ciphers and is last cipher is the result of a recursive modulo 10 operation ran over the rest of it. Shorten form with - is also accepted. Raise a ValidationError if check fails """ if not postal_acc_number: raise ValidationError(_("There is no postal account number.")) if re.match('^[0-9]{2}-[0-9]{1,6}-[0-9]$', postal_acc_number): ref_subparts = postal_acc_number.split('-') postal_acc_number = (ref_subparts[0] + ref_subparts[1].rjust(6, '0') + ref_subparts[2]) if not re.match(r'\d{9}$', postal_acc_number or ''): msg = _("The postal does not match 9 digits position.") raise ValidationError(msg) acc_number_without_check = postal_acc_number[:-1] if not mod10r(acc_number_without_check) == postal_acc_number: raise ValidationError(_("The postal account number is not valid."))
def action_date_assign(self): """Method called when invoice is validated. - Add BVR Reference if payment mode is LSV and no reference is set. - Prevent validating invoices missing related contract. """ for invoice in self.filtered("payment_mode_id"): if "LSV" in invoice.payment_mode_id.name and not invoice.reference: seq = self.env["ir.sequence"] ref = mod10r(seq.next_by_code("contract.bvr.ref")) invoice.write({"reference": ref}) for invl in invoice.invoice_line_ids: if not invl.contract_id and invl.product_id.categ_name in ( SPONSORSHIP_CATEGORY, GIFT_CATEGORY, ): raise UserError( _("Invoice %s for '%s' is missing a sponsorship.") % (str(invoice.id), invoice.partner_id.name)) return super().action_date_assign()
def compute_partner_bvr_ref(self, partner=None, is_lsv=False): """ Generates a new BVR Reference. See file /nas/it/devel/Code_ref_BVR.xls for more information.""" self.ensure_one() if self.exists(): # If group was already existing, retrieve any existing reference ref = self.bvr_reference if ref: return ref partner = partner or self.partner_id result = "0" * (9 + (7 - len(partner.ref))) + partner.ref count_groups = str(self.search_count([("partner_id", "=", partner.id)])) result += "0" * (5 - len(count_groups)) + count_groups # Type '0' = Sponsorship result += "0" result += "0" * 4 if is_lsv: result = "004874969" + result[9:] if len(result) == 26: return mod10r(result)
def get_scan_line(self, account, reference, amount=False): """ Generate a scan line given the reference """ if amount: line = "01" decimal_amount, int_amount = math.modf(amount) str_amount = (str(int(int_amount)) + str(int(decimal_amount * 100)).rjust(2, '0')).rjust( 10, '0') line += str_amount line = mod10r(line) else: line = "042" line += ">" line += reference.replace(" ", "").rjust(27, '0') line += '+ ' account_components = account.split('-') bank_identifier = "%s%s%s" % (account_components[0], account_components[1].rjust( 6, '0'), account_components[2]) line += bank_identifier line += '>' return line
def get_scan_line(self, account, reference, amount=False): """ Generate a scan line given the reference """ if amount: line = "01" decimal_amount, int_amount = math.modf(amount) str_amount = (str(int(int_amount)) + str(int(decimal_amount * 100)).rjust(2, "0")).rjust( 10, "0") line += str_amount line = mod10r(line) else: line = "042" line += ">" line += reference.replace(" ", "").rjust(27, "0") line += "+ " account_components = account.split("-") bank_identifier = (f"{account_components[0]}" f"{account_components[1].rjust(6, '0')}" f"{account_components[2]}") line += bank_identifier line += ">" return line
def compute_partner_bvr_ref(self, partner=None, is_lsv=False): """ Generates a new BVR Reference. See file /nas/it/devel/Code_ref_BVR.xls for more information.""" self.ensure_one() if self.exists(): # If group was already existing, retrieve any existing reference ref = self.bvr_reference if ref: return ref partner = partner or self.partner_id result = '0' * (9 + (7 - len(partner.ref))) + partner.ref count_groups = str(self.search_count( [('partner_id', '=', partner.id)])) result += '0' * (5 - len(count_groups)) + count_groups # Type '0' = Sponsorship result += '0' result += '0' * 4 if is_lsv: result = '004874969' + result[9:] if len(result) == 26: return mod10r(result)
def generate_bvr_reference(self, contract, product): product = product.with_context(lang='en_US') ref = contract.gift_partner_id.ref bvr_reference = '0' * (9 + (7 - len(ref))) + ref commitment_number = str(contract.commitment_number) bvr_reference += '0' * (5 - len(commitment_number)) + commitment_number # Type of gift bvr_reference += str(GIFT_NAMES.index(product.name) + 1) bvr_reference += '0' * 4 if contract.payment_mode_id and 'LSV' in contract.payment_mode_id.name: # Get company BVR adherent number user = self.env.user bank_obj = self.env['res.partner.bank'] company_bank = bank_obj.search([ ('partner_id', '=', user.company_id.partner_id.id), ('bvr_adherent_num', '!=', False)]) if company_bank: bvr_reference = company_bank.bvr_adherent_num +\ bvr_reference[9:] if len(bvr_reference) == 26: return mod10r(bvr_reference) return False
def _compute_l10n_ch_isr_number(self): r"""Generates the ISR or QRR reference An ISR references are 27 characters long. QRR is a recycling of ISR for QR-bills. Thus works the same. The invoice sequence number is used, removing each of its non-digit characters, and pad the unused spaces on the left of this number with zeros. The last digit is a checksum (mod10r). There are 2 types of references: * ISR (Postfinance) The reference is free but for the last digit which is a checksum. If shorter than 27 digits, it is filled with zeros on the left. e.g. 120000000000234478943216899 \________________________/| 1 2 (1) 12000000000023447894321689 | reference (2) 9: control digit for identification number and reference * ISR-B (Indirect through a bank, requires a customer ID) In case of ISR-B The firsts digits (usually 6), contain the customer ID at the Bank of this ISR's issuer. The rest (usually 20 digits) is reserved for the reference plus the control digit. If the [customer ID] + [the reference] + [the control digit] is shorter than 27 digits, it is filled with zeros between the customer ID till the start of the reference. e.g. 150001123456789012345678901 \____/\__________________/| 1 2 3 (1) 150001 | id number of the customer (size may vary) (2) 12345678901234567890 | reference (3) 1: control digit for identification number and reference """ for record in self: if (record._need_isr_ref()) and record.number: id_number = record._get_isrb_id_number() if id_number: id_number = id_number.zfill(l10n_ch_ISR_ID_NUM_LENGTH) invoice_ref = re.sub(r'[^\d]', '', record.number) # keep only the last digits if it exceed boundaries full_len = len(id_number) + len(invoice_ref) ref_payload_len = l10n_ch_ISR_NUMBER_LENGTH - 1 extra = full_len - ref_payload_len if extra > 0: invoice_ref = invoice_ref[extra:] internal_ref = invoice_ref.zfill(ref_payload_len - len(id_number)) record.l10n_ch_isr_number = mod10r(id_number + internal_ref) else: record.l10n_ch_isr_number = False