support Warenpost International API
there's an updated inema module, supporting a new Warenpost International API; let's add support for it here.
This commit is contained in:
parent
5df351493e
commit
824d432937
|
@ -3,6 +3,7 @@ import logging
|
|||
from openerp.exceptions import Warning
|
||||
import pycountry
|
||||
from inema import Internetmarke
|
||||
from inema import WarenpostInt
|
||||
|
||||
_logger = logging.getLogger(__name__)
|
||||
|
||||
|
@ -86,6 +87,141 @@ class DPDeliveryCarrier(models.Model):
|
|||
last = last,
|
||||
address = addr)
|
||||
|
||||
def conn_auth_wpi(self):
|
||||
"""Connect to the Warenpost International API"""
|
||||
config = self._get_config()
|
||||
partner_id = config['dp_partner_id']
|
||||
key = config['dp_key']
|
||||
key_phase = config['dp_key_phase']
|
||||
pk_user = config['dp_portokasse_user']
|
||||
pk_passwd = config['dp_portokasse_passwd']
|
||||
ekp = config['dp_wpi_ekp']
|
||||
use_sandbox = config['dp_wpi_sandbox']
|
||||
print(__name__)
|
||||
print(partner_id, key, ekp, pk_user, pk_passwd, key_phase, use_sandbox)
|
||||
wpi = WarenpostInt(partner_id, key, ekp, pk_user, pk_passwd, key_phase, use_sandbox)
|
||||
wpi.get_token()
|
||||
return wpi
|
||||
|
||||
def build_wpi_addr(self, wpi, partner):
|
||||
"""Build a WarenpostInt.Address object from an Odoo partner object."""
|
||||
|
||||
def trim_phone(ph):
|
||||
if not ph:
|
||||
return None
|
||||
if len(ph) <= 15:
|
||||
return ph
|
||||
ph = ph.replace('-','')
|
||||
ph = ph.replace(' ','')
|
||||
return ph
|
||||
|
||||
wpi_addr_lines = []
|
||||
if partner.is_company:
|
||||
wpi_name = partner.name
|
||||
else:
|
||||
if partner.parent_id.name:
|
||||
wpi_name = partner.parent_id.name
|
||||
if partner.name:
|
||||
wpi_addr_lines.append(partner.name)
|
||||
else:
|
||||
wpi_name = partner.name
|
||||
wpi_addr_lines.append(partner.street)
|
||||
if partner.street2:
|
||||
wpi_addr_lines.append(partner.street2)
|
||||
wpi_phone = trim_phone(partner.phone)
|
||||
wpi_fax = trim_phone(partner.fax)
|
||||
wpi_state = partner.state_id.name if partner.state_id else None
|
||||
return wpi.Address(wpi_name, wpi_addr_lines, partner.city, partner.country_id.code,
|
||||
partner.zip, wpi_state, wpi_phone, wpi_fax, partner.email)
|
||||
|
||||
def build_wpi_content_item(self, wpi, line):
|
||||
"""Build contentPiece from Odoo stock.move (line of a picking)."""
|
||||
product_uom_obj = self.env['product.uom']
|
||||
q = product_uom_obj._compute_qty_obj(self._get_default_uom(), line.product_uom_qty, self.uom_id)
|
||||
product = line.product_id
|
||||
if product:
|
||||
if product.x_sysmo_customs_code:
|
||||
hts = product.x_sysmo_customs_code
|
||||
else:
|
||||
raise Warning('Product Variant %s has no HTS defined' % (product.name))
|
||||
if product.x_country_of_origin:
|
||||
orig = product.x_country_of_origin.code
|
||||
elif line.product_tmpl_id and line.product_tmpl_id.x_country_of_origin:
|
||||
orig = line.product_tmpl_id.x_country_of_origin.code
|
||||
else:
|
||||
raise Warning('Product Variant %s has no Country of Origin defined' % (product.name))
|
||||
weight = product.weight
|
||||
elif line.product_tmpl_id:
|
||||
ptmpl = line.product_tmpl_id
|
||||
if ptempl.x_sysmo_default_customs_code:
|
||||
hts = ptempl.x_sysmo_default_customs_code
|
||||
else:
|
||||
raise Warning('Product %s has no HTS defined' % (ptempl.name))
|
||||
if ptempl.x_country_of_origin:
|
||||
orig = ptempl.x_country_of_origin.code
|
||||
else:
|
||||
raise Warning('Product %s has no Country of Origin defined' % (ptempl.name))
|
||||
weight = ptempl.weight
|
||||
if line.procurement_id and line.procurement_id.sale_line_id:
|
||||
price_unit = line.procurement_id.sale_line_id.price_unit
|
||||
else:
|
||||
raise Warning('Line has no procurement or procurement no sale order line?!?')
|
||||
weight_g = weight * 1000
|
||||
line_value = q * price_unit
|
||||
return wpi.build_content_item(weight_g, line_value, q, hts, orig, product.name)
|
||||
|
||||
def build_wpi_content(self, wpi, picking):
|
||||
"""Build contentPieces from Odoo stock.picking."""
|
||||
content = [self.build_wpi_content_item(wpi, x) for x in picking.move_lines]
|
||||
total = 0.0
|
||||
for i in content:
|
||||
total += float(i['contentPieceValue'])
|
||||
return (content, total)
|
||||
|
||||
@api.one
|
||||
def wpi_send_shipping(self, pickings):
|
||||
config = self._get_config()
|
||||
order = self.env['sale.order'].search([('name','=',pickings.origin)])
|
||||
recipient = pickings.partner_id
|
||||
warehouse = pickings.picking_type_id.warehouse_id.partner_id
|
||||
# determine weight and DP service/product
|
||||
weight = self._get_weight(order, pickings)
|
||||
service = self.get_service_by_class(recipient, weight, self.dp_service_class)
|
||||
if not service:
|
||||
raise Warning("Service not available for weight!")
|
||||
# connect to API
|
||||
wpi = self.conn_auth_wpi()
|
||||
# build various data structures for the API
|
||||
wpi_recipient = self.build_wpi_addr(wpi, recipient)
|
||||
wpi_sender = self.build_wpi_addr(wpi, warehouse)
|
||||
if self._country_code_outside_eu(recipient.country_id.code):
|
||||
(wpi_content, total_value) = self.build_wpi_content(wpi, pickings)
|
||||
else:
|
||||
wpi_content = []
|
||||
total_value = 0
|
||||
wpi_item = wpi.build_item(service.code, wpi_sender, wpi_recipient, weight*1000, total_value,
|
||||
'EUR', customer_reference=pickings.name, contents=wpi_content)
|
||||
# actually create the order + download the label
|
||||
wpi_res = wpi.api_create_order([wpi_item], 'Max Mustermann')
|
||||
wpi_res_item = wpi_res['shipments'][0]['items'][0]
|
||||
png = wpi.api_get_item_label(wpi_res_item['id'], 'image/png')
|
||||
# build result dict
|
||||
awb = wpi_res['shipments'][0]['awb']
|
||||
voucher_id = wpi_res_item['voucherId']
|
||||
filename = 'WPI'+voucher_id+'.png'
|
||||
tracking_nr = ' '
|
||||
if 'barcode' in wpi_res_item:
|
||||
tracking_nr += wpi_res_item['barcode']
|
||||
result = { 'exact_price': service.cost_price,
|
||||
'weight': service.weight,
|
||||
'date_delivery': None,
|
||||
'tracking_number': tracking_nr,
|
||||
'voucher_id' : voucher_id,
|
||||
'order_id' : awb,
|
||||
'attachments': [(filename, png)]}
|
||||
_logger.debug(result)
|
||||
return result
|
||||
|
||||
def _get_eu_res_country_group(self):
|
||||
eu_group = self.env.ref("base.europe", raise_if_not_found=False)
|
||||
if not eu_group:
|
||||
|
@ -99,11 +235,21 @@ class DPDeliveryCarrier(models.Model):
|
|||
else:
|
||||
eu_country_group = self._get_eu_res_country_group()
|
||||
country_id = self.env['res.country'].search([('code','=',country_code)])
|
||||
if country_id in eu_country_group.country_ids.ids:
|
||||
if country_id.id in eu_country_group.country_ids.ids:
|
||||
return service_class.services_eu
|
||||
else:
|
||||
return service_class.services_intl
|
||||
|
||||
def _country_code_outside_eu(self, country_code):
|
||||
"""Is the specified two-digit country code outside the EU?"""
|
||||
if country_code == 'DE':
|
||||
return False
|
||||
eu_country_group = self._get_eu_res_country_group()
|
||||
country_id = self.env['res.country'].search([('code','=',country_code)])
|
||||
if country_id.id in eu_country_group.country_ids.ids:
|
||||
return False
|
||||
return True
|
||||
|
||||
# determine lowest-matching-max-weight service within same class
|
||||
def get_service_by_class(self, recipient, weight, service_class):
|
||||
services = self.get_services_by_country(service_class, recipient.country_id.code)
|
||||
|
@ -126,6 +272,8 @@ class DPDeliveryCarrier(models.Model):
|
|||
|
||||
@api.one
|
||||
def dp_send_shipping(self, pickings):
|
||||
if self.dp_service_class.is_wpi:
|
||||
return self.wpi_send_shipping(pickings)[0]
|
||||
config = self._get_config()
|
||||
order = self.env['sale.order'].search([('name','=',pickings.origin)])
|
||||
recipient = pickings.partner_id
|
||||
|
|
|
@ -10,6 +10,7 @@ class SMCShippingDp(models.Model):
|
|||
class SMCShippingDpClass(models.Model):
|
||||
_name = "delivery.carrier.dp.class"
|
||||
name = fields.Char(string="Name", required=1)
|
||||
is_wpi = fields.Boolean("Warenpost International")
|
||||
# list of services in this class for national delivery
|
||||
services_natl = fields.Many2many(comodel_name = 'delivery.carrier.dp.service',
|
||||
relation = 'dp_class_natl_services_rel')
|
||||
|
|
|
@ -12,6 +12,8 @@ class website_config_settings(models.Model):
|
|||
dp_key_phase = fields.Char('Key Phase', required=1)
|
||||
dp_portokasse_user = fields.Char('Portokasse User', required=1)
|
||||
dp_portokasse_passwd = fields.Char('Portokasse Password', required=1)
|
||||
dp_wpi_ekp = fields.Char('EKP Number', required=1)
|
||||
dp_wpi_sandbox = fields.Boolean('Use WPI Sandbox environment')
|
||||
|
||||
@api.model
|
||||
def get_default_dp_values(self, fields):
|
||||
|
@ -31,4 +33,6 @@ class website_config_settings(models.Model):
|
|||
ir_values.set_default('delivery.carrier', 'dp_key_phase', config.dp_key_phase or '')
|
||||
ir_values.set_default('delivery.carrier', 'dp_portokasse_user', config.dp_portokasse_user or '')
|
||||
ir_values.set_default('delivery.carrier', 'dp_portokasse_passwd', config.dp_portokasse_passwd or '')
|
||||
ir_values.set_default('delivery.carrier', 'dp_wpi_ekp', config.dp_wpi_ekp or '')
|
||||
ir_values.set_default('delivery.carrier', 'dp_wpi_sandbox', config.dp_wpi_sandbox or True)
|
||||
return True
|
||||
|
|
|
@ -83,6 +83,7 @@
|
|||
<form>
|
||||
<sheet>
|
||||
<field name="name"/>
|
||||
<field name="is_wpi"/>
|
||||
<field name="services_natl"/>
|
||||
<field name="services_eu"/>
|
||||
<field name="services_intl"/>
|
||||
|
@ -97,6 +98,7 @@
|
|||
<field name="arch" type="xml">
|
||||
<tree string="package">
|
||||
<field name="name"/>
|
||||
<field name="is_wpi"/>
|
||||
<field name="services_natl"/>
|
||||
<field name="services_eu"/>
|
||||
<field name="services_intl"/>
|
||||
|
|
|
@ -15,6 +15,10 @@
|
|||
<field name="dp_portokasse_user" class="oe_inline"/>
|
||||
<field name="dp_portokasse_passwd" class="oe_inline"/>
|
||||
</group>
|
||||
<group string="Warenpost International">
|
||||
<field name="dp_wpi_ekp" class="oe_inline"/>
|
||||
<field name="dp_wpi_sandbox" class="oe_inline"/>
|
||||
</group>
|
||||
</sheet>
|
||||
<footer>
|
||||
<button string="Apply" type="object" name="execute" class="oe_highlight"/>
|
||||
|
|
Loading…
Reference in New Issue