Support UPS international invoice form
This commit is contained in:
1 parent
0796f27fbd
commit
791d649dde
17 files changed
+497
-3
No files matched your search
@@ -1,3 +1,4 @@
|
||||
* Support international invoice form
|
||||
* Use "General Merchandise" as fallback shipping description
|
||||
|
||||
Version 7.6.0 - 2025-04-28
|
||||
|
||||
@@ -22,6 +22,7 @@ class CredentialUPS(sequence_ordered(), ModelSQL, ModelView, MatchMixin):
|
||||
client_secret = fields.Char("Client Secret", required=True)
|
||||
account_number = fields.Char('Account Number', required=True)
|
||||
use_metric = fields.Boolean('Use Metric')
|
||||
use_international_forms = fields.Boolean("Use International Forms")
|
||||
server = fields.Selection([
|
||||
('testing', 'Testing'),
|
||||
('production', 'Production'),
|
||||
@@ -41,6 +42,10 @@ class CredentialUPS(sequence_ordered(), ModelSQL, ModelView, MatchMixin):
|
||||
def default_use_metric(cls):
|
||||
return True
|
||||
|
||||
@classmethod
|
||||
def default_use_international_forms(cls):
|
||||
return False
|
||||
|
||||
@classmethod
|
||||
def default_server(cls):
|
||||
return 'testing'
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
# This file is part of Tryton. The COPYRIGHT file at the top level of
|
||||
# this repository contains the full copyright notices and license terms.
|
||||
|
||||
from trytond.model import fields
|
||||
from trytond.pool import PoolMeta
|
||||
|
||||
|
||||
class Agent(metaclass=PoolMeta):
|
||||
__name__ = 'customs.agent'
|
||||
|
||||
ups_account_number = fields.Char("UPS Account Number")
|
||||
@@ -0,0 +1,18 @@
|
||||
<?xml version="1.0"?>
|
||||
<!-- This file is part of Tryton. The COPYRIGHT file at the top level of
|
||||
this repository contains the full copyright notices and license terms. -->
|
||||
<tryton>
|
||||
<data depends="customs">
|
||||
<record model="ir.ui.view" id="customs_agent_view_form">
|
||||
<field name="model">customs.agent</field>
|
||||
<field name="inherit" ref="customs.customs_agent_view_form"/>
|
||||
<field name="name">customs_agent_form</field>
|
||||
</record>
|
||||
|
||||
<record model="ir.ui.view" id="customs_agent_view_list">
|
||||
<field name="model">customs.agent</field>
|
||||
<field name="inherit" ref="customs.customs_agent_view_list"/>
|
||||
<field name="name">customs_agent_list</field>
|
||||
</record>
|
||||
</data>
|
||||
</tryton>
|
||||
@@ -0,0 +1,56 @@
|
||||
# This file is part of Tryton. The COPYRIGHT file at the top level of
|
||||
# this repository contains the full copyright notices and license terms.
|
||||
|
||||
from trytond.model import fields
|
||||
from trytond.pool import PoolMeta
|
||||
|
||||
|
||||
class UoM(metaclass=PoolMeta):
|
||||
__name__ = 'product.uom'
|
||||
|
||||
ups_code = fields.Selection([
|
||||
('BA', "Barrel"),
|
||||
('BE', "Bundle"),
|
||||
('BG', "Bag"),
|
||||
('BH', "Bunch"),
|
||||
('BOX', "Box"),
|
||||
('BT', "Bolt"),
|
||||
('BU', "Butt"),
|
||||
('CI', "Canister"),
|
||||
('CM', "Centimeter"),
|
||||
('CON', "Container"),
|
||||
('CR', "Crate"),
|
||||
('CS', "Case"),
|
||||
('CT', "Carton"),
|
||||
('CY', "Cylinder"),
|
||||
('DOZ', "Dozen"),
|
||||
('EA', "Each"),
|
||||
('EN', "Envelope"),
|
||||
('FT', "Feet"),
|
||||
('KG', "Kilogram"),
|
||||
('KGS', "Kilograms"),
|
||||
('LB', "Pound"),
|
||||
('LBS', "Pounds"),
|
||||
('L', "Liter"),
|
||||
('M', "Meter"),
|
||||
('NMB', "Number"),
|
||||
('PA', "Packet"),
|
||||
('PAL', "Pallet"),
|
||||
('PC', "Piece"),
|
||||
('PCS', "Pieces"),
|
||||
('PF', "Proof Liters"),
|
||||
('PKG', "Package"),
|
||||
('PR', "Pair"),
|
||||
('PRS', "Pairs"),
|
||||
('RL', "Roll"),
|
||||
('SET', "Set"),
|
||||
('SME', "Square Meters"),
|
||||
('SYD', "Square Yards"),
|
||||
('TU', "Tube"),
|
||||
('YD', "Yard"),
|
||||
('OTH', "Other"),
|
||||
], "UPS Code", required=True)
|
||||
|
||||
@classmethod
|
||||
def default_ups_code(cls):
|
||||
return 'OTH'
|
||||
@@ -0,0 +1,41 @@
|
||||
<?xml version="1.0"?>
|
||||
<!-- This file is part of Tryton. The COPYRIGHT file at the top level of
|
||||
this repository contains the full copyright notices and license terms. -->
|
||||
<tryton>
|
||||
<data>
|
||||
<record model="ir.ui.view" id="product_uom_view_form">
|
||||
<field name="model">product.uom</field>
|
||||
<field name="inherit" ref="product.uom_view_form"/>
|
||||
<field name="name">product_uom_form</field>
|
||||
</record>
|
||||
</data>
|
||||
<data noupdate="1">
|
||||
<record model="product.uom" id="product.uom_unit">
|
||||
<field name="ups_code">PC</field>
|
||||
</record>
|
||||
<record model="product.uom" id="product.uom_kilogram">
|
||||
<field name="ups_code">KG</field>
|
||||
</record>
|
||||
<record model="product.uom" id="product.uom_pound">
|
||||
<field name="ups_code">LB</field>
|
||||
</record>
|
||||
<record model="product.uom" id="product.uom_meter">
|
||||
<field name="ups_code">M</field>
|
||||
</record>
|
||||
<record model="product.uom" id="product.uom_centimeter">
|
||||
<field name="ups_code">CM</field>
|
||||
</record>
|
||||
<record model="product.uom" id="product.uom_yard">
|
||||
<field name="ups_code">YD</field>
|
||||
</record>
|
||||
<record model="product.uom" id="product.uom_liter">
|
||||
<field name="ups_code">L</field>
|
||||
</record>
|
||||
<record model="product.uom" id="product.uom_square_meter">
|
||||
<field name="ups_code">SME</field>
|
||||
</record>
|
||||
<record model="product.uom" id="product.uom_square_yard">
|
||||
<field name="ups_code">SYD</field>
|
||||
</record>
|
||||
</data>
|
||||
</tryton>
|
||||
@@ -52,8 +52,11 @@ requires.append(get_require_version('trytond'))
|
||||
|
||||
tests_require = [
|
||||
get_require_version('proteus'),
|
||||
get_require_version('trytond_customs'),
|
||||
get_require_version('trytond_incoterm'),
|
||||
get_require_version('trytond_sale'),
|
||||
get_require_version('trytond_sale_shipment_cost'),
|
||||
get_require_version('trytond_stock_shipment_customs'),
|
||||
]
|
||||
|
||||
setup(name=name,
|
||||
|
||||
@@ -5,6 +5,7 @@ import base64
|
||||
import re
|
||||
import ssl
|
||||
import urllib.parse
|
||||
from decimal import Decimal
|
||||
from itertools import zip_longest
|
||||
from math import ceil
|
||||
|
||||
@@ -396,3 +397,126 @@ class CreateShippingUPS(Wizard):
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
class CreateShippingUPS_Customs_Incoterm(metaclass=PoolMeta):
|
||||
__name__ = 'stock.shipment.create_shipping.ups'
|
||||
|
||||
def get_request(self, shipment, packages, credential):
|
||||
request = super().get_request(shipment, packages, credential)
|
||||
if (shipment.customs_international
|
||||
and credential.use_international_forms):
|
||||
international_form = self.get_international_form(
|
||||
shipment, credential)
|
||||
request['ShipmentRequest']['Shipment'].setdefault(
|
||||
'ShipmentServiceOptions', {})['InternationalForms'] = (
|
||||
international_form)
|
||||
return request
|
||||
|
||||
def get_international_form(self, shipment, credential):
|
||||
form_type = self.get_international_form_type(shipment, credential)
|
||||
return getattr(self, f'get_international_form_{form_type}')(
|
||||
credential.use_metric, shipment)
|
||||
|
||||
def get_international_form_type(self, shipment, credential):
|
||||
return 'invoice'
|
||||
|
||||
def get_international_form_invoice(self, use_metric, shipment):
|
||||
pool = Pool()
|
||||
Date = pool.get('ir.date')
|
||||
|
||||
with Transaction().set_context(company=shipment.company.id):
|
||||
today = Date.today()
|
||||
|
||||
if customs_agent := shipment.customs_agent:
|
||||
sold_to_party = customs_agent.party
|
||||
sold_to_address = customs_agent.address
|
||||
else:
|
||||
sold_to_party = shipment.shipping_to
|
||||
sold_to_address = shipment.shipping_to_address
|
||||
|
||||
invoice_date = shipment.effective_date or today
|
||||
currency, = {m.currency for m in shipment.customs_moves}
|
||||
sold_to = self.get_shipping_party(sold_to_party, sold_to_address)
|
||||
if customs_agent:
|
||||
sold_to['AccountNumber'] = customs_agent.ups_account_number
|
||||
return {
|
||||
'FormType': '01', # Invoice
|
||||
'Contacts': {
|
||||
'SoldTo': sold_to,
|
||||
},
|
||||
'Product': [
|
||||
self.get_international_form_invoice_product(
|
||||
use_metric, shipment, *k, **v)
|
||||
for k, v in shipment.customs_products.items()],
|
||||
'InvoiceNumber': shipment.number[-35:],
|
||||
'InvoiceDate': invoice_date.strftime('%Y%m%d'),
|
||||
'TermsOfShipment': (
|
||||
shipment.incoterm.code if shipment.incoterm else None),
|
||||
'ReasonForExport': self.get_international_form_invoice_reason(
|
||||
shipment),
|
||||
'CurrencyCode': currency.code,
|
||||
}
|
||||
|
||||
def get_international_form_invoice_product(
|
||||
self, use_metric, shipment, product, price, currency, unit,
|
||||
quantity, weight):
|
||||
pool = Pool()
|
||||
UoM = pool.get('product.uom')
|
||||
ModelData = pool.get('ir.model.data')
|
||||
|
||||
kg = UoM(ModelData.get_id('product', 'uom_kilogram'))
|
||||
lb = UoM(ModelData.get_id('product', 'uom_pound'))
|
||||
|
||||
tariff_code = product.get_tariff_code({
|
||||
'date': shipment.effective_date or shipment.planned_date,
|
||||
'country': (
|
||||
shipment.customs_to_country.id
|
||||
if shipment.customs_to_country else None),
|
||||
})
|
||||
weight = UoM.compute_qty(
|
||||
kg, weight, kg if use_metric else lb, round=False)
|
||||
if len(str(weight)) > 5:
|
||||
weight = ceil(weight)
|
||||
|
||||
if not quantity.is_integer():
|
||||
value = price * Decimal(str(quantity))
|
||||
quantity = 1
|
||||
unit_code = 'OTH'
|
||||
else:
|
||||
value = price
|
||||
unit_code = unit.ups_code
|
||||
|
||||
for i in range(6, -1, -1):
|
||||
value = str(price.quantize(Decimal(10) ** -i)).rstrip('0')
|
||||
if len(value) <= 19:
|
||||
break
|
||||
return {
|
||||
'Description': product.name[:35],
|
||||
'Unit': {
|
||||
'Number': '%i' % quantity,
|
||||
'UnitOfMeasurement': {
|
||||
'Code': unit_code,
|
||||
'Description': (
|
||||
unit.ups_code if unit.ups_code != 'OTH'
|
||||
else unit.name)[:3],
|
||||
},
|
||||
'Value': value,
|
||||
},
|
||||
'CommodityCode': tariff_code.code if tariff_code else None,
|
||||
'OriginCountryCode': (
|
||||
product.country_of_origin.code if product.country_of_origin
|
||||
else None),
|
||||
'ProductWeight': {
|
||||
'UnitOfMeasurement': {
|
||||
'Code': 'KGS' if use_metric else 'LBS',
|
||||
},
|
||||
'Weight': str(weight),
|
||||
},
|
||||
}
|
||||
|
||||
def get_international_form_invoice_reason(self, shipment):
|
||||
return {
|
||||
'stock.shipment.out': 'SALE',
|
||||
'stock.shipment.in.return': 'RETURN',
|
||||
}.get(shipment.__class__.__name__)
|
||||
@@ -175,7 +175,7 @@ Create a UPS Carrier and the related credential::
|
||||
>>> carrier.party = ups
|
||||
>>> carrier.carrier_product = carrier_product
|
||||
>>> carrier.shipping_service = 'ups'
|
||||
>>> carrier.ups_service_type = '65'
|
||||
>>> carrier.ups_service_type = '11'
|
||||
>>> carrier.ups_label_image_format = 'GIF'
|
||||
>>> carrier.ups_notifications = ['5', '7', '012']
|
||||
>>> carrier.save()
|
||||
@@ -204,7 +204,6 @@ Create the packs and ship the shipment::
|
||||
|
||||
>>> Package = Model.get('stock.package')
|
||||
>>> shipment, = sale.shipments
|
||||
>>> shipment.shipping_description = 'Football Players'
|
||||
>>> shipment.click('assign_try')
|
||||
>>> shipment.click('pick')
|
||||
>>> pack = shipment.packages.new()
|
||||
|
||||
+187
@@ -0,0 +1,187 @@
|
||||
======================================================
|
||||
Stock Package Shipping with UPS International Scenario
|
||||
======================================================
|
||||
|
||||
Imports::
|
||||
|
||||
>>> import os
|
||||
>>> from decimal import Decimal
|
||||
|
||||
>>> from proteus import Model
|
||||
>>> from trytond.modules.company.tests.tools import create_company, get_company
|
||||
>>> from trytond.tests.tools import activate_modules, assertEqual
|
||||
|
||||
Activate modules::
|
||||
|
||||
>>> config = activate_modules(
|
||||
... ['stock_package_shipping_ups', 'stock_shipment_customs'],
|
||||
... create_company)
|
||||
|
||||
>>> Agent = Model.get('customs.agent')
|
||||
>>> AgentSelection = Model.get('customs.agent.selection')
|
||||
>>> Address = Model.get('party.address')
|
||||
>>> Carrier = Model.get('carrier')
|
||||
>>> Country = Model.get('country.country')
|
||||
>>> Location = Model.get('stock.location')
|
||||
>>> Package = Model.get('stock.package')
|
||||
>>> PackageType = Model.get('stock.package.type')
|
||||
>>> Party = Model.get('party.party')
|
||||
>>> ProductTemplate = Model.get('product.template')
|
||||
>>> Shipment = Model.get('stock.shipment.out')
|
||||
>>> UPSCredential = Model.get('carrier.credential.ups')
|
||||
>>> UoM = Model.get('product.uom')
|
||||
|
||||
Get company::
|
||||
|
||||
>>> company = get_company()
|
||||
|
||||
Create countries::
|
||||
|
||||
>>> belgium = Country(code='BE', name="Belgium")
|
||||
>>> belgium.save()
|
||||
>>> switzerland = Country(code='CH', name="Switerland")
|
||||
>>> switzerland.save()
|
||||
>>> taiwan = Country(code='TW', name="Taiwan")
|
||||
>>> taiwan.save()
|
||||
|
||||
Create parties::
|
||||
|
||||
>>> customer = Party(name="Customer")
|
||||
>>> customer_address, = customer.addresses
|
||||
>>> customer_address.street = "Pfistergasse 17"
|
||||
>>> customer_address.postal_code = "6003"
|
||||
>>> customer_address.city = "Lucerna"
|
||||
>>> customer_address.country = switzerland
|
||||
>>> customer_phone = customer.contact_mechanisms.new()
|
||||
>>> customer_phone.type = 'phone'
|
||||
>>> customer_phone.value = "+(41) (041) 410-62-66"
|
||||
>>> customer_email = customer.contact_mechanisms.new()
|
||||
>>> customer_email.type = 'email'
|
||||
>>> customer_email.value = 'customer@example.com'
|
||||
>>> customer.save()
|
||||
|
||||
>>> agent_party = Party(name="Agent")
|
||||
>>> agent_address, = agent_party.addresses
|
||||
>>> agent_address.street = "Gerechtigkeitsgasse 53"
|
||||
>>> agent_address.postal_code = "3011"
|
||||
>>> agent_address.city = "Berna"
|
||||
>>> agent_address.country = switzerland
|
||||
>>> agent_identifier = agent_party.identifiers.new()
|
||||
>>> agent_identifier.type = 'ch_vat'
|
||||
>>> agent_identifier.code = "CHE-123.456.788 IVA"
|
||||
>>> agent_party.save()
|
||||
>>> agent = Agent(party=agent_party)
|
||||
>>> agent.save()
|
||||
>>> AgentSelection(to_country=switzerland, agent=agent).save()
|
||||
|
||||
Set the warehouse address::
|
||||
|
||||
>>> warehouse, = Location.find([('type', '=', 'warehouse')])
|
||||
>>> company_address = Address()
|
||||
>>> company_address.party = company.party
|
||||
>>> company_address.street = '2 rue de la Centrale'
|
||||
>>> company_address.postal_code = '4000'
|
||||
>>> company_address.city = 'Sclessin'
|
||||
>>> company_address.country = belgium
|
||||
>>> company_address.save()
|
||||
>>> company_phone = company.party.contact_mechanisms.new()
|
||||
>>> company_phone.type = 'phone'
|
||||
>>> company_phone.value = '+32 4 2522122'
|
||||
>>> company_phone.save()
|
||||
>>> warehouse.address = company_address
|
||||
>>> warehouse.save()
|
||||
|
||||
Get some units::
|
||||
|
||||
>>> unit, = UoM.find([('name', '=', "Unit")], limit=1)
|
||||
>>> cm, = UoM.find([('name', '=', "Centimeter")], limit=1)
|
||||
>>> gram, = UoM.find([('name', '=', "Gram")], limit=1)
|
||||
|
||||
Create product::
|
||||
|
||||
>>> template = ProductTemplate()
|
||||
>>> template.name = "Product"
|
||||
>>> template.default_uom = unit
|
||||
>>> template.type = 'goods'
|
||||
>>> template.weight = 100
|
||||
>>> template.weight_uom = gram
|
||||
>>> template.list_price = Decimal('10.0000')
|
||||
>>> template.country_of_origin = taiwan
|
||||
>>> template.save()
|
||||
>>> product, = template.products
|
||||
|
||||
Create Package Type::
|
||||
|
||||
>>> ups_box = PackageType(
|
||||
... name='UPS Box', ups_code='02',
|
||||
... length=10, length_uom=cm,
|
||||
... height=8, height_uom=cm,
|
||||
... width=1, width_uom=cm)
|
||||
>>> ups_box.save()
|
||||
|
||||
Create a UPS Carrier and the related credential::
|
||||
|
||||
>>> credential = UPSCredential()
|
||||
>>> credential.company = company
|
||||
>>> credential.client_id = os.getenv('UPS_CLIENT_ID')
|
||||
>>> credential.client_secret = os.getenv('UPS_CLIENT_SECRET')
|
||||
>>> credential.account_number = os.getenv('UPS_ACCOUNT_NUMBER')
|
||||
>>> credential.server = 'testing'
|
||||
>>> credential.use_international_forms = True
|
||||
>>> credential.save()
|
||||
|
||||
>>> carrier_product_template = ProductTemplate()
|
||||
>>> carrier_product_template.name = 'UPS Ground'
|
||||
>>> carrier_product_template.default_uom = unit
|
||||
>>> carrier_product_template.type = 'service'
|
||||
>>> carrier_product_template.list_price = Decimal(20)
|
||||
>>> carrier_product_template.save()
|
||||
>>> carrier_product, = carrier_product_template.products
|
||||
|
||||
>>> ups = Party(name='UPS')
|
||||
>>> ups.save()
|
||||
|
||||
>>> carrier = Carrier()
|
||||
>>> carrier.party = ups
|
||||
>>> carrier.carrier_product = carrier_product
|
||||
>>> carrier.shipping_service = 'ups'
|
||||
>>> carrier.ups_service_type = '65'
|
||||
>>> carrier.ups_label_image_format = 'GIF'
|
||||
>>> carrier.ups_notifications = ['5', '7', '012']
|
||||
>>> carrier.save()
|
||||
|
||||
Create a shipment::
|
||||
|
||||
>>> shipment = Shipment()
|
||||
>>> shipment.customer = customer
|
||||
>>> shipment.carrier = carrier
|
||||
>>> shipment.shipping_description = "Shipping description"
|
||||
>>> move = shipment.outgoing_moves.new()
|
||||
>>> move.product = product
|
||||
>>> move.unit = unit
|
||||
>>> move.quantity = 2
|
||||
>>> move.from_location = shipment.warehouse_output
|
||||
>>> move.to_location = shipment.customer_location
|
||||
>>> move.unit_price = Decimal('50.0000')
|
||||
>>> move.currency = company.currency
|
||||
>>> shipment.click('wait')
|
||||
>>> assertEqual(shipment.customs_agent, agent)
|
||||
>>> shipment.click('assign_force')
|
||||
>>> shipment.click('pick')
|
||||
>>> shipment.state
|
||||
'picked'
|
||||
|
||||
Create the packs and ship the shipment::
|
||||
|
||||
>>> pack = shipment.packages.new()
|
||||
>>> pack.type = ups_box
|
||||
>>> pack_move, = pack.moves.find([])
|
||||
>>> pack.moves.append(pack_move)
|
||||
>>> shipment.click('pack')
|
||||
>>> shipment.state
|
||||
'packed'
|
||||
|
||||
>>> create_shipping = shipment.click('create_shipping')
|
||||
>>> shipment.reload()
|
||||
>>> bool(shipment.shipping_reference)
|
||||
True
|
||||
@@ -7,6 +7,7 @@ from trytond.tests.test_tryton import ModuleTestCase
|
||||
class ShippingUpsTestCase(ModuleTestCase):
|
||||
'Test Shipping Ups module'
|
||||
module = 'stock_package_shipping_ups'
|
||||
extras = ['customs', 'incoterm', 'stock_shipment_customs']
|
||||
|
||||
|
||||
del ModuleTestCase
|
||||
@@ -11,5 +11,8 @@ def load_tests(*args, **kwargs):
|
||||
or not (os.getenv('UPS_CLIENT_ID')
|
||||
and os.getenv('UPS_CLIENT_SECRET')
|
||||
and os.getenv('UPS_ACCOUNT_NUMBER'))):
|
||||
kwargs.setdefault('skips', set()).add('scenario_shipping_ups.rst')
|
||||
kwargs.setdefault('skips', set()).update([
|
||||
'scenario_shipping_ups.rst',
|
||||
'scenario_stock_package_shipping_ups_international.rst',
|
||||
])
|
||||
return load_doc_tests(__name__, __file__, *args, **kwargs)
|
||||
@@ -10,13 +10,20 @@ depends:
|
||||
stock_shipment_measurements
|
||||
stock_package
|
||||
stock_package_shipping
|
||||
extras_depend:
|
||||
customs
|
||||
incoterm
|
||||
stock_shipment_customs
|
||||
xml:
|
||||
product.xml
|
||||
carrier.xml
|
||||
customs.xml
|
||||
stock.xml
|
||||
message.xml
|
||||
|
||||
[register]
|
||||
model:
|
||||
product.UoM
|
||||
carrier.CredentialUPS
|
||||
carrier.Carrier
|
||||
stock.PackageType
|
||||
@@ -25,5 +32,13 @@ wizard:
|
||||
stock.CreateShipping
|
||||
stock.CreateShippingUPS
|
||||
|
||||
[register customs]
|
||||
model:
|
||||
customs.Agent
|
||||
|
||||
[register incoterm stock_shipment_customs]
|
||||
wizard:
|
||||
stock.CreateShippingUPS_Customs_Incoterm
|
||||
|
||||
[register_mixin]
|
||||
stock.ShippingUPSMixin: trytond.modules.stock_package_shipping.stock.ShippingMixin
|
||||
@@ -0,0 +1,10 @@
|
||||
<?xml version="1.0"?>
|
||||
<!-- This file is part of Tryton. The COPYRIGHT file at the top level of
|
||||
this repository contains the full copyright notices and license terms. -->
|
||||
<data>
|
||||
<xpath expr="//field[@name='tax_identifier']" position="after">
|
||||
<label name="ups_account_number"/>
|
||||
<field name="ups_account_number"/>
|
||||
<newline/>
|
||||
</xpath>
|
||||
</data>
|
||||
@@ -0,0 +1,8 @@
|
||||
<?xml version="1.0"?>
|
||||
<!-- This file is part of Tryton. The COPYRIGHT file at the top level of
|
||||
this repository contains the full copyright notices and license terms. -->
|
||||
<data>
|
||||
<xpath expr="//field[@name='tax_identifier']" position="after">
|
||||
<field name="ups_account_number" optional="1"/>
|
||||
</xpath>
|
||||
</data>
|
||||
@@ -0,0 +1,10 @@
|
||||
<?xml version="1.0"?>
|
||||
<!-- This file is part of Tryton. The COPYRIGHT file at the top level of
|
||||
this repository contains the full copyright notices and license terms. -->
|
||||
<data>
|
||||
<xpath expr="//field[@name='digits']" position="after">
|
||||
<label name="ups_code"/>
|
||||
<field name="ups_code"/>
|
||||
<newline/>
|
||||
</xpath>
|
||||
</data>
|
||||
@@ -14,6 +14,8 @@ this repository contains the full copyright notices and license terms. -->
|
||||
|
||||
<label name="use_metric"/>
|
||||
<field name="use_metric"/>
|
||||
<label name="use_international_forms"/>
|
||||
<field name="use_international_forms"/>
|
||||
|
||||
<separator string="Credential Information" colspan="4" id="credential_info"/>
|
||||
<label name="client_id"/>
|
||||
|
||||
Reference in new issue
Block a user