mirror of
https://github.com/OCA/bank-payment.git
synced 2025-02-02 10:37:31 +02:00
Merge US&CA changes from canonical
This commit is contained in:
@@ -384,7 +384,7 @@
|
||||
<field name="type">form</field>
|
||||
<field name="arch" type="xml">
|
||||
<field name="bic" position="replace">
|
||||
<field name="bic" on_change="onchange_bic(bic, name)"/>
|
||||
<field name="bic" />
|
||||
</field>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
@@ -17,5 +17,13 @@
|
||||
<field name="ir_model_id"
|
||||
ref="account_banking_uk_hsbc.model_banking_export_hsbc_wizard"/>
|
||||
</record>
|
||||
<record model="payment.mode.type" id="export_priority_payment">
|
||||
<field name="name">Priority Payment</field>
|
||||
<field name="code">not used</field>
|
||||
<field name="suitable_bank_types"
|
||||
eval="[(6,0,[ref('base_iban.bank_iban'),ref('base.bank_normal'),])]" />
|
||||
<field name="ir_model_id"
|
||||
ref="account_banking_uk_hsbc.model_banking_export_hsbc_wizard"/>
|
||||
</record>
|
||||
</data>
|
||||
</openerp>
|
||||
|
||||
@@ -38,7 +38,7 @@ class transaction(models.mem_bank_transaction):
|
||||
|
||||
mapping = {
|
||||
'execution_date' : 'valuedate',
|
||||
'effective_date' : 'bookingdate',
|
||||
'effective_date' : 'valuedate',
|
||||
'local_currency' : 'currency',
|
||||
'transfer_type' : 'bookingcode',
|
||||
'reference' : 'custrefno',
|
||||
|
||||
@@ -28,6 +28,7 @@ from decimal import Decimal
|
||||
import paymul
|
||||
import string
|
||||
import random
|
||||
import netsvc
|
||||
|
||||
def strpdate(arg, format='%Y-%m-%d'):
|
||||
'''shortcut'''
|
||||
@@ -98,6 +99,8 @@ class banking_export_hsbc_wizard(osv.osv_memory):
|
||||
),
|
||||
}
|
||||
|
||||
logger = netsvc.Logger()
|
||||
|
||||
def create(self, cursor, uid, wizard_data, context=None):
|
||||
'''
|
||||
Retrieve a sane set of default values based on the payment orders
|
||||
@@ -139,8 +142,14 @@ class banking_export_hsbc_wizard(osv.osv_memory):
|
||||
def _create_account(self, oe_account):
|
||||
currency = None # let the receiving bank select the currency from the batch
|
||||
holder = oe_account.owner_name or oe_account.partner_id.name
|
||||
self.logger.notifyChannel('paymul', netsvc.LOG_INFO,'Create account %s' % (holder))
|
||||
self.logger.notifyChannel('paymul', netsvc.LOG_INFO,'-- %s' % (oe_account.country_id.code))
|
||||
self.logger.notifyChannel('paymul', netsvc.LOG_INFO,'-- %s' % (oe_account.acc_number))
|
||||
self.logger.notifyChannel('paymul', netsvc.LOG_INFO,'-- %s' % (oe_account.iban))
|
||||
|
||||
|
||||
if oe_account.iban:
|
||||
self.logger.notifyChannel('paymul', netsvc.LOG_INFO,'IBAN: %s' % (oe_account.iban))
|
||||
paymul_account = paymul.IBANAccount(
|
||||
iban=oe_account.iban,
|
||||
bic=oe_account.bank.bic,
|
||||
@@ -151,6 +160,7 @@ class banking_export_hsbc_wizard(osv.osv_memory):
|
||||
'charges': paymul.CHARGES_EACH_OWN,
|
||||
}
|
||||
elif oe_account.country_id.code == 'GB':
|
||||
self.logger.notifyChannel('paymul', netsvc.LOG_INFO,'GB: %s %s' % (oe_account.country_id.code,oe_account.acc_number))
|
||||
split = oe_account.acc_number.split(" ", 2)
|
||||
if len(split) == 2:
|
||||
sortcode, accountno = split
|
||||
@@ -167,11 +177,53 @@ class banking_export_hsbc_wizard(osv.osv_memory):
|
||||
transaction_kwargs = {
|
||||
'charges': paymul.CHARGES_PAYEE,
|
||||
}
|
||||
else:
|
||||
raise osv.except_osv(
|
||||
_('Error'),
|
||||
_('%s: only UK accounts and IBAN are supported') % (holder)
|
||||
elif oe_account.country_id.code in ('US','CA'):
|
||||
self.logger.notifyChannel('paymul', netsvc.LOG_INFO,'US/CA: %s %s' % (oe_account.country_id.code,oe_account.acc_number))
|
||||
split = oe_account.acc_number.split(' ', 2)
|
||||
if len(split) == 2:
|
||||
sortcode, accountno = split
|
||||
else:
|
||||
raise osv.except_osv(
|
||||
_('Error'),
|
||||
"Invalid %s account number '%s'" % (oe_account.country_id.code,oe_account.acc_number))
|
||||
paymul_account = paymul.NorthAmericanAccount(
|
||||
number=accountno,
|
||||
sortcode=sortcode,
|
||||
holder=holder,
|
||||
currency=currency,
|
||||
swiftcode=oe_account.bank.bic,
|
||||
country=oe_account.country_id.code,
|
||||
#origin_country=origin_country
|
||||
)
|
||||
transaction_kwargs = {
|
||||
'charges': paymul.CHARGES_PAYEE,
|
||||
}
|
||||
transaction_kwargs = {
|
||||
'charges': paymul.CHARGES_PAYEE,
|
||||
}
|
||||
else:
|
||||
self.logger.notifyChannel('paymul', netsvc.LOG_INFO,'SWIFT Account: %s' % (oe_account.country_id.code))
|
||||
split = oe_account.acc_number.split(' ', 2)
|
||||
if len(split) == 2:
|
||||
sortcode, accountno = split
|
||||
else:
|
||||
raise osv.except_osv(
|
||||
_('Error'),
|
||||
"Invalid %s account number '%s'" % (oe_account.country_id.code,oe_account.acc_number))
|
||||
paymul_account = paymul.SWIFTAccount(
|
||||
number=accountno,
|
||||
sortcode=sortcode,
|
||||
holder=holder,
|
||||
currency=currency,
|
||||
swiftcode=oe_account.bank.bic,
|
||||
country=oe_account.country_id.code,
|
||||
)
|
||||
transaction_kwargs = {
|
||||
'charges': paymul.CHARGES_PAYEE,
|
||||
}
|
||||
transaction_kwargs = {
|
||||
'charges': paymul.CHARGES_PAYEE,
|
||||
}
|
||||
|
||||
return paymul_account, transaction_kwargs
|
||||
|
||||
@@ -185,14 +237,19 @@ class banking_export_hsbc_wizard(osv.osv_memory):
|
||||
'number must be provided'
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
self.logger.notifyChannel('paymul', netsvc.LOG_INFO, '====')
|
||||
dest_account, transaction_kwargs = self._create_account(line.bank_id)
|
||||
|
||||
means = {'ACH or EZONE': paymul.MEANS_ACH_OR_EZONE,
|
||||
'Faster Payment': paymul.MEANS_FASTER_PAYMENT}.get(line.order_id.mode.type.name)
|
||||
'Faster Payment': paymul.MEANS_FASTER_PAYMENT,
|
||||
'Priority Payment': paymul.MEANS_PRIORITY_PAYMENT}.get(line.order_id.mode.type.name)
|
||||
if means is None:
|
||||
raise osv.except_osv('Error', "Invalid payment type mode for HSBC '%s'" % line.order_id.mode.type.name)
|
||||
|
||||
if not line.info_partner:
|
||||
raise osv.except_osv('Error', "No default address for transaction '%s'" % line.name)
|
||||
|
||||
try:
|
||||
return paymul.Transaction(
|
||||
amount=Decimal(str(line.amount_currency)),
|
||||
@@ -221,6 +278,7 @@ class banking_export_hsbc_wizard(osv.osv_memory):
|
||||
|
||||
|
||||
try:
|
||||
self.logger.notifyChannel('paymul', netsvc.LOG_INFO,'Source - %s (%s) %s' % (payment_orders[0].mode.bank_id.partner_id.name, payment_orders[0].mode.bank_id.acc_number, payment_orders[0].mode.bank_id.country_id.code))
|
||||
src_account = self._create_account(
|
||||
payment_orders[0].mode.bank_id,
|
||||
)[0]
|
||||
@@ -237,11 +295,12 @@ class banking_export_hsbc_wizard(osv.osv_memory):
|
||||
"account number (not IBAN)" + str(type(src_account)))
|
||||
)
|
||||
|
||||
transactions = []
|
||||
for po in payment_orders:
|
||||
transactions += [self._create_transaction(l) for l in po.line_ids]
|
||||
|
||||
try:
|
||||
self.logger.notifyChannel('paymul', netsvc.LOG_INFO, 'Create transactions...')
|
||||
transactions = []
|
||||
for po in payment_orders:
|
||||
transactions += [self._create_transaction(l) for l in po.line_ids]
|
||||
|
||||
batch = paymul.Batch(
|
||||
exec_date=strpdate(wizard_data.execution_date_create),
|
||||
reference=wizard_data.reference,
|
||||
|
||||
@@ -23,6 +23,10 @@ from account_banking import sepa
|
||||
from decimal import Decimal
|
||||
import datetime
|
||||
import re
|
||||
import unicodedata
|
||||
|
||||
def strip_accents(string):
|
||||
return unicodedata.normalize('NFKD', unicode(string)).encode('ASCII', 'ignore')
|
||||
|
||||
def split_account_holder(holder):
|
||||
holder_parts = holder.split("\n")
|
||||
@@ -40,13 +44,19 @@ The standard says alphanumeric characters, but spaces are also allowed
|
||||
def edifact_isalnum(s):
|
||||
return bool(re.match(r'^[A-Za-z0-9 ]*$', s))
|
||||
|
||||
def edifact_digits(val, digits, mindigits=None):
|
||||
def edifact_digits(val, digits=None, mindigits=None):
|
||||
if digits is None:
|
||||
digits = ''
|
||||
if mindigits is None:
|
||||
mindigits = digits
|
||||
|
||||
pattern = r'^[0-9]{' + str(mindigits) + ',' + str(digits) + r'}$'
|
||||
return bool(re.match(pattern, str(val)))
|
||||
|
||||
def edifact_isalnum_size(val, digits):
|
||||
pattern = r'^[A-Za-z0-9 ]{' + str(digits) + ',' + str(digits) + r'}$'
|
||||
return bool(re.match(pattern, str(val)))
|
||||
|
||||
class HasCurrency(object):
|
||||
def _get_currency(self):
|
||||
return self._currency
|
||||
@@ -73,14 +83,14 @@ class LogicalSection(object):
|
||||
segments = self.segments()
|
||||
|
||||
def format_segment(segment):
|
||||
return '+'.join([':'.join([str(y) for y in x]) for x in segment]) + "'"
|
||||
return '+'.join([':'.join([str(strip_accents(y)) for y in x]) for x in segment]) + "'"
|
||||
|
||||
return "\n".join([format_segment(s) for s in segments])
|
||||
|
||||
|
||||
def _fii_segment(self, party_qualifier):
|
||||
holder = split_account_holder(self.holder)
|
||||
account_identification = [self.number, holder[0]]
|
||||
account_identification = [self.number.replace(' ',''), holder[0]]
|
||||
if holder[1] or self.currency:
|
||||
account_identification.append(holder[1])
|
||||
if self.currency:
|
||||
@@ -126,16 +136,16 @@ class UKAccount(HasCurrency):
|
||||
holder_parts = split_account_holder(holder)
|
||||
|
||||
if not len(holder_parts[0]) <= 35:
|
||||
raise ValueError("Account holder must be <= 35 characters long")
|
||||
raise ValueError("Account holder must be <= 35 characters long: " + str(holder_parts[0]))
|
||||
|
||||
if not len(holder_parts[1]) <= 35:
|
||||
raise ValueError("Second line of account holder must be <= 35 characters long")
|
||||
raise ValueError("Second line of account holder must be <= 35 characters long: " + str(holder_parts[1]))
|
||||
|
||||
if not edifact_isalnum(holder_parts[0]):
|
||||
raise ValueError("Account holder must be alphanumeric")
|
||||
raise ValueError("Account holder must be alphanumeric: " + str(holder_parts[0]))
|
||||
|
||||
if not edifact_isalnum(holder_parts[1]):
|
||||
raise ValueError("Second line of account holder must be alphanumeric")
|
||||
raise ValueError("Second line of account holder must be alphanumeric: " + str(holder_parts[1]))
|
||||
|
||||
self._holder = holder.upper()
|
||||
|
||||
@@ -155,6 +165,113 @@ class UKAccount(HasCurrency):
|
||||
def fii_or_segment(self):
|
||||
return _fii_segment(self, 'OR')
|
||||
|
||||
|
||||
class NorthAmericanAccount(UKAccount):
|
||||
|
||||
def _set_account_ident(self):
|
||||
if self.origin_country in ('US','CA'):
|
||||
# Use the routing number
|
||||
account_ident = ['', '', '', self.sortcode, 155, 114]
|
||||
else:
|
||||
# Using the BIC/Swift Code
|
||||
account_ident = [self.bic, 25, 5, '', '', '']
|
||||
return account_ident
|
||||
|
||||
def _set_sortcode(self, sortcode):
|
||||
if not edifact_digits(sortcode, 9):
|
||||
raise ValueError("Account routing number must be 9 digits long: " +
|
||||
str(sortcode))
|
||||
|
||||
|
||||
self._sortcode = sortcode
|
||||
|
||||
def _get_sortcode(self):
|
||||
return self._sortcode
|
||||
|
||||
sortcode = property(_get_sortcode, _set_sortcode)
|
||||
|
||||
def _set_bic(self, bic):
|
||||
if not edifact_isalnum_size(bic, 8) and not edifact_isalnum_size(bic, 11):
|
||||
raise ValueError("Account BIC/Swift code must be 8 or 11 characters long: " +
|
||||
str(bic))
|
||||
self._bic = bic
|
||||
|
||||
def _get_bic(self):
|
||||
return self._bic
|
||||
|
||||
bic = property(_get_bic, _set_bic)
|
||||
|
||||
def _set_number(self, number):
|
||||
if not edifact_digits(number, mindigits=1):
|
||||
raise ValueError("Account number is invalid: " +
|
||||
str(number))
|
||||
|
||||
self._number = number
|
||||
|
||||
def _get_number(self):
|
||||
return self._number
|
||||
|
||||
number = property(_get_number, _set_number)
|
||||
|
||||
def __init__(self, number, holder, currency, sortcode, swiftcode, country, origin_country=None):
|
||||
self.number = number
|
||||
self.holder = holder
|
||||
self.currency = currency
|
||||
self.sortcode = sortcode
|
||||
self.country = country
|
||||
self.bic = swiftcode
|
||||
self.origin_country = origin_country
|
||||
self.institution_identification = self._set_account_ident()
|
||||
|
||||
|
||||
class SWIFTAccount(UKAccount):
|
||||
|
||||
def _set_account_ident(self):
|
||||
# Using the BIC/Swift Code
|
||||
return [self.bic, 25, 5, '', '', '']
|
||||
|
||||
def _set_sortcode(self, sortcode):
|
||||
self._sortcode = sortcode
|
||||
|
||||
def _get_sortcode(self):
|
||||
return self._sortcode
|
||||
|
||||
sortcode = property(_get_sortcode, _set_sortcode)
|
||||
|
||||
def _set_bic(self, bic):
|
||||
if not edifact_isalnum_size(bic, 8) and not edifact_isalnum_size(bic, 11):
|
||||
raise ValueError("Account BIC/Swift code must be 8 or 11 characters long: " +
|
||||
str(bic))
|
||||
self._bic = bic
|
||||
|
||||
def _get_bic(self):
|
||||
return self._bic
|
||||
|
||||
bic = property(_get_bic, _set_bic)
|
||||
|
||||
def _set_number(self, number):
|
||||
if not edifact_digits(number, mindigits=1):
|
||||
raise ValueError("Account number is invalid: " +
|
||||
str(number))
|
||||
|
||||
self._number = number
|
||||
|
||||
def _get_number(self):
|
||||
return self._number
|
||||
|
||||
number = property(_get_number, _set_number)
|
||||
|
||||
def __init__(self, number, holder, currency, sortcode, swiftcode, country, origin_country=None):
|
||||
self.number = number
|
||||
self.holder = holder
|
||||
self.currency = currency
|
||||
self.sortcode = sortcode
|
||||
self.country = country
|
||||
self.bic = swiftcode
|
||||
self.origin_country = origin_country
|
||||
self.institution_identification = self._set_account_ident()
|
||||
|
||||
|
||||
class IBANAccount(HasCurrency):
|
||||
def _get_iban(self):
|
||||
return self._iban
|
||||
@@ -162,7 +279,7 @@ class IBANAccount(HasCurrency):
|
||||
def _set_iban(self, iban):
|
||||
iban_obj = sepa.IBAN(iban)
|
||||
if not iban_obj.valid:
|
||||
raise ValueError("IBAN is invalid")
|
||||
raise ValueError("IBAN is invalid: " + str(iban))
|
||||
|
||||
self._iban = iban
|
||||
self.country = iban_obj.countrycode
|
||||
@@ -186,10 +303,10 @@ class Interchange(LogicalSection):
|
||||
|
||||
def _set_reference(self, reference):
|
||||
if not len(reference) <= 15:
|
||||
raise ValueError("Reference must be <= 15 characters long")
|
||||
raise ValueError("Reference must be <= 15 characters long: " + str(reference))
|
||||
|
||||
if not edifact_isalnum(reference):
|
||||
raise ValueError("Reference must be alphanumeric")
|
||||
raise ValueError("Reference must be alphanumeric: " + str(reference))
|
||||
|
||||
self._reference = reference.upper()
|
||||
|
||||
@@ -226,10 +343,10 @@ class Message(LogicalSection):
|
||||
|
||||
def _set_reference(self, reference):
|
||||
if not len(reference) <= 35:
|
||||
raise ValueError("Reference must be <= 35 characters long")
|
||||
raise ValueError("Reference must be <= 35 characters long: " + str(reference))
|
||||
|
||||
if not edifact_isalnum(reference):
|
||||
raise ValueError("Reference must be alphanumeric")
|
||||
raise ValueError("Reference must be alphanumeric: " + str(reference))
|
||||
|
||||
self._reference = reference.upper()
|
||||
|
||||
@@ -285,10 +402,10 @@ class Batch(LogicalSection):
|
||||
|
||||
def _set_reference(self, reference):
|
||||
if not len(reference) <= 18:
|
||||
raise ValueError("Reference must be <= 18 characters long")
|
||||
raise ValueError("Reference must be <= 18 characters long: " + str(reference))
|
||||
|
||||
if not edifact_isalnum(reference):
|
||||
raise ValueError("Reference must be alphanumeric")
|
||||
raise ValueError("Reference must be alphanumeric: " + str(reference))
|
||||
|
||||
self._reference = reference.upper()
|
||||
|
||||
@@ -306,41 +423,78 @@ class Batch(LogicalSection):
|
||||
|
||||
def segments(self, index):
|
||||
if not edifact_digits(index, 6, 1):
|
||||
raise ValueError("Index must be 6 digits or less")
|
||||
raise ValueError("Index must be 6 digits or less: " + str(index))
|
||||
|
||||
# Store the payment means
|
||||
means = None
|
||||
if len(self.transactions)>0:
|
||||
means = self.transactions[0].means
|
||||
|
||||
segments = []
|
||||
|
||||
segments.append([
|
||||
['LIN'],
|
||||
[index],
|
||||
])
|
||||
segments.append([
|
||||
['DTM'],
|
||||
[203, self.exec_date.strftime('%Y%m%d'), 102],
|
||||
])
|
||||
segments.append([
|
||||
['RFF'],
|
||||
['AEK', self.reference],
|
||||
])
|
||||
|
||||
currencies = set([x.currency for x in self.transactions])
|
||||
if len(currencies) > 1:
|
||||
raise ValueError("All transactions in a batch must have the same currency")
|
||||
|
||||
segments.append([
|
||||
['MOA'],
|
||||
[9, self.amount().quantize(Decimal('0.00')), currencies.pop()],
|
||||
])
|
||||
segments.append(self.debit_account.fii_or_segment())
|
||||
segments.append([
|
||||
['NAD'],
|
||||
['OY'],
|
||||
[''],
|
||||
self.name_address.upper().split("\n")[0:5],
|
||||
])
|
||||
if means != MEANS_PRIORITY_PAYMENT:
|
||||
segments.append([
|
||||
['LIN'],
|
||||
[index],
|
||||
])
|
||||
segments.append([
|
||||
['DTM'],
|
||||
[203, self.exec_date.strftime('%Y%m%d'), 102],
|
||||
])
|
||||
segments.append([
|
||||
['RFF'],
|
||||
['AEK', self.reference],
|
||||
])
|
||||
|
||||
currencies = set([x.currency for x in self.transactions])
|
||||
if len(currencies) > 1:
|
||||
raise ValueError("All transactions in a batch must have the same currency")
|
||||
|
||||
segments.append([
|
||||
['MOA'],
|
||||
[9, self.amount().quantize(Decimal('0.00')), currencies.pop()],
|
||||
])
|
||||
segments.append(self.debit_account.fii_or_segment())
|
||||
segments.append([
|
||||
['NAD'],
|
||||
['OY'],
|
||||
[''],
|
||||
self.name_address.upper().split("\n")[0:5],
|
||||
])
|
||||
|
||||
for index, transaction in enumerate(self.transactions):
|
||||
segments += transaction.segments(index + 1)
|
||||
if transaction.means == MEANS_PRIORITY_PAYMENT:
|
||||
# Need a debit-credit format for Priority Payments
|
||||
segments.append([
|
||||
['LIN'],
|
||||
[index+1],
|
||||
])
|
||||
segments.append([
|
||||
['DTM'],
|
||||
[203, self.exec_date.strftime('%Y%m%d'), 102],
|
||||
])
|
||||
segments.append([
|
||||
['RFF'],
|
||||
['AEK', self.reference],
|
||||
])
|
||||
|
||||
# Use the transaction amount and currency for the debit line
|
||||
segments.append([
|
||||
['MOA'],
|
||||
[9, transaction.amount.quantize(Decimal('0.00')), transaction.currency],
|
||||
])
|
||||
segments.append(self.debit_account.fii_or_segment())
|
||||
segments.append([
|
||||
['NAD'],
|
||||
['OY'],
|
||||
[''],
|
||||
self.name_address.upper().split("\n")[0:5],
|
||||
])
|
||||
use_index = 1
|
||||
else:
|
||||
use_index = index + 1
|
||||
|
||||
segments += transaction.segments(use_index)
|
||||
|
||||
return segments
|
||||
|
||||
@@ -367,7 +521,7 @@ class Transaction(LogicalSection, HasCurrency):
|
||||
|
||||
def _set_amount(self, amount):
|
||||
if len(str(amount)) > 18:
|
||||
raise ValueError("Amount must be shorter than 18 bytes")
|
||||
raise ValueError("Amount must be shorter than 18 bytes: " + str(amount))
|
||||
|
||||
self._amount = amount
|
||||
|
||||
@@ -378,10 +532,10 @@ class Transaction(LogicalSection, HasCurrency):
|
||||
|
||||
def _set_payment_reference(self, payment_reference):
|
||||
if not len(payment_reference) <= 18:
|
||||
raise ValueError("Payment reference must be <= 18 characters long")
|
||||
raise ValueError("Payment reference must be <= 18 characters long: " + str(payment_reference))
|
||||
|
||||
if not edifact_isalnum(payment_reference):
|
||||
raise ValueError("Payment reference must be alphanumeric")
|
||||
raise ValueError("Payment reference must be alphanumeric: " + str(payment_reference))
|
||||
|
||||
self._payment_reference = payment_reference.upper()
|
||||
|
||||
@@ -392,10 +546,10 @@ class Transaction(LogicalSection, HasCurrency):
|
||||
|
||||
def _set_customer_reference(self, customer_reference):
|
||||
if not len(customer_reference) <= 18:
|
||||
raise ValueError("Customer reference must be <= 18 characters long")
|
||||
raise ValueError("Customer reference must be <= 18 characters long: " + str(customer_reference))
|
||||
|
||||
if not edifact_isalnum(customer_reference):
|
||||
raise ValueError("Customer reference must be alphanumeric")
|
||||
raise ValueError("Customer reference must be alphanumeric: " + str(customer_reference))
|
||||
|
||||
self._customer_reference = customer_reference.upper()
|
||||
|
||||
@@ -472,3 +626,4 @@ class Transaction(LogicalSection, HasCurrency):
|
||||
segments.append(nad_segment)
|
||||
|
||||
return segments
|
||||
|
||||
|
||||
Reference in New Issue
Block a user