Odoo integration of Deutsche Post Internetmarke Online Franking
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

176 lines
7.2 KiB

from openerp import api, fields, models
import logging
from openerp.exceptions import Warning
import pycountry
from inema import Internetmarke
_logger = logging.getLogger(__name__)
TRACKING_URL = 'https://www.deutschepost.de/sendung/simpleQuery.html?locale=en_GB'
# convert from ISO3166 2-digit to 3-digit
def get_alpha3_country_from_alpha2(twodigit):
c = pycountry.countries.get(alpha2=twodigit)
return c.alpha3
# split the last word of a string containing stree name + house number
def split_street_house(streethouse):
# first try to split at last space
r = streethouse.rsplit(' ', 1)
# if that fails, try to split at last dot
if len(r) < 2:
r = streethouse.rsplit('.', 1)
# if that also fails, return empty house number
if len(r) < 2:
return (streethouse, '')
return (r[0], r[1])
def split_first_lastname(name):
# try to split at last space
r = name.rsplit(' ', 1)
# if this fails, simply claim everything is the last name
if len(r) < 2:
return ("", name)
return (r[0], r[1])
class DPDeliveryCarrier(models.Model):
_inherit="delivery.carrier"
def conn_auth_im(self):
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']
im = Internetmarke(partner_id, key, key_phase)
im.authenticate(pk_user, pk_passwd)
return im
# Convert an Odoo Partner object into Internetmarke Address
def build_im_addr(self, im, partner):
(street, house) = split_street_house(partner.street)
country = get_alpha3_country_from_alpha2(partner.country_id.code)
street2 = None
if partner.street2:
street2 = partner.street2
addr = im.build_addr(street = street,
house = house,
additional = street2,
zipcode = partner.zip,
city = partner.city,
country = country)
if partner.is_company:
return im.build_comp_addr(company = partner.name,
address = addr)
else:
if partner.parent_id.name:
person = None
if partner.name:
(first, last) = split_first_lastname(partner.name)
title = None
if partner.title and partner.title.shortcut:
title = partner.title.shortcut
person = im.build_pers_name(first=first, last=last, title=title)
return im.build_comp_addr(company = partner.parent_id.name,
address = addr,
person = person)
else:
(first, last) = split_first_lastname(partner.name)
return im.build_pers_addr(first = first,
last = last,
address = addr)
def get_services_by_country(self, service_class, country_code):
if country_code == 'DE':
return service_class.services_natl
else:
return service_class.services_intl
# 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)
lowest_max_weight = 100000
lowest_service = None
for s in services:
if s.weight >= weight and s.weight < lowest_max_weight:
lowest_max_weight = s.weight
lowest_service = s
return lowest_service
# determine the maximum weight (in kg) of any service in this class
def get_class_max_weight(self, service_class):
services = self.get_services_by_country(service_class, recipient.country_id.code)
highest_weight = 0
for s in services:
if highest_weight > hightest_weight:
highest_weight = s.weight
return highest_weight
@api.one
def dp_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
weight = self._get_weight(order, pickings)
service = self.get_service_by_class(recipient, weight, self.sudo().dp_service_class)
if not service:
raise Warning("Service not available for weight!")
im = self.conn_auth_im()
im_recipient = self.build_im_addr(im, recipient)
im_sender = self.build_im_addr(im, warehouse)
im.clear_positions()
position = im.build_position(service.code, im_sender, im_recipient)
im.add_position(position)
if im.wallet_balance < im.compute_total():
raise Warning("Wallet balance %f is less than label cost %f!" % (im.wallet_balance/100, im.compute_total()/100)
r = im.checkoutPNG()
voucher = r.shoppingCart.voucherList.voucher[0]
filename = 'DP'+voucher.voucherId+'.png'
tracking_nr = ' '
if voucher.trackId:
tracking_nr += voucher.trackId
result = { 'exact_price': im.compute_total()/100,
'weight': service.weight,
'date_delivery': None,
'tracking_number': tracking_nr,
'voucher_id' : voucher.voucherId,
'order_id' : r.shoppingCart.shopOrderId,
'wallet_balance': r.walletBallance,
'attachments': [(filename, voucher.png_bin)]}
return result
def dp_get_shipping_price_from_so(self, order):
price = 0
config = self._get_config()
recipient = order.partner_shipping_id if order.partner_shipping_id else order.partner_id
warehouse = order.warehouse_id.partner_id
service_class = self.sudo().dp_service_class
# single-package implementation
weight = self._get_weight(order)
service = self.get_service_by_class(recipient, weight, service_class)
if not service:
raise Warning("Service not available for weight!")
return service.cost_price
# compute the maximum weight of any service within class
#class_max_weight = self.get_class_max_weight(service_class)
# compute number of packages and each weight
#weight, weight_limit, last_package, limits = self.get_package_count(class_max_weight, order)
# iterate over list of packages
#for line in range(1, limits+1):
# if last_package and line == limits:
# weight_limit = last_package
# service = self.get_service_by_class(recipient, weight, service_class)
# price += service.cost_price
#return price
@api.one
def dp_get_tracking_link(self, pickings):
return TRACKING_URL
@api.one
def dp_cancel_shipment(self, pickings):
raise Warning('Cancelling DP Shipments not supported!')