|
|
|
@ -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 |
|
|
|
|