# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
import json
import requests
from markupsafe import Markup
from werkzeug.urls import url_join
from odoo import api, fields, models, _
from odoo.exceptions import UserError
from odoo.tools.float_utils import float_round
from odoo.tools import file_open
from .easypost_request import EasypostRequest
class DeliverCarrier(models.Model):
_inherit = 'delivery.carrier'
delivery_type = fields.Selection(selection_add=[
('easypost', 'Easypost')
], ondelete={'easypost': lambda recs: recs.write({'delivery_type': 'fixed', 'fixed_price': 0})})
easypost_test_api_key = fields.Char("Test API Key", groups="base.group_system", help="Enter your API test key from Easypost account.")
easypost_production_api_key = fields.Char("Production API Key", groups="base.group_system", help="Enter your API production key from Easypost account")
easypost_delivery_type = fields.Char('Easypost Carrier Type')
easypost_delivery_type_id = fields.Char('Easypost Carrier Type ID, technical for API request')
easypost_default_package_type_id = fields.Many2one("stock.package.type", string="Default Package Type for Easypost", domain="[('easypost_carrier', '=', easypost_delivery_type)]")
easypost_default_service_id = fields.Many2one("easypost.service", string="Default Service Level", help="If not set, the less expensive available service level will be chosen.", domain="[('easypost_carrier', '=', easypost_delivery_type)]")
easypost_label_file_type = fields.Selection([
('PNG', 'PNG'), ('PDF', 'PDF'),
('ZPL', 'ZPL'), ('EPL2', 'EPL2')],
string="Easypost Label File Type", default='PDF')
easypost_insurance_fee_rate = fields.Float("Insurance fee rate (USD)")
easypost_insurance_fee_minimum = fields.Float("Insurance fee minimum (USD)")
def _compute_can_generate_return(self):
super(DeliverCarrier, self)._compute_can_generate_return()
for carrier in self:
if carrier.delivery_type == 'easypost':
carrier.can_generate_return = True
def _compute_supports_shipping_insurance(self):
res = super(DeliverCarrier, self)._compute_supports_shipping_insurance()
for carrier in self:
if carrier.delivery_type == 'easypost':
carrier.supports_shipping_insurance = True
return res
def action_get_carrier_type(self):
""" Return the list of carriers configured by the customer
on its easypost account.
"""
if self.delivery_type == 'easypost' and self.sudo().easypost_production_api_key:
ep = EasypostRequest(self.sudo().easypost_production_api_key, self.log_xml)
carriers = ep.fetch_easypost_carrier()
if carriers:
action = self.env["ir.actions.actions"]._for_xml_id("delivery_easypost.act_delivery_easypost_carrier_type")
action['context'] = {
'carrier_types': carriers,
'default_delivery_carrier_id': self.id,
}
return action
else:
raise UserError(_('A production key is required in order to load your easypost carriers.'))
def easypost_rate_shipment(self, order):
""" Return the rates for a quotation/SO."""
ep = EasypostRequest(self.sudo().easypost_production_api_key if self.prod_environment else self.sudo().easypost_test_api_key, self.log_xml)
response = ep.rate_request(self, order.partner_shipping_id, order.warehouse_id.partner_id, order)
# Return error message
if response.get('error_message'):
return {
'success': False,
'price': 0.0,
'error_message': response.get('error_message'),
'warning_message': False
}
# Update price with the order currency
rate = response.get('rate')
if order.currency_id.name == rate['currency']:
price = float(rate['rate'])
else:
quote_currency = self.env['res.currency'].search([('name', '=', rate['currency'])], limit=1)
price = quote_currency._convert(float(rate['rate']), order.currency_id, self.env.company, fields.Date.context_today(self))
# Update price with the insurance cost
insurance_cost = response.get('insurance_cost', 0)
usd = self.env.ref('base.USD')
price += usd._convert(insurance_cost, order.currency_id, self.env.company, fields.Date.context_today(self))
return {
'success': True,
'price': price,
'error_message': False,
'warning_message': response.get('warning_message', False)
}
def easypost_send_shipping(self, pickings):
""" It creates an easypost order and buy it with the selected rate on
delivery method or cheapest rate if it is not set. It will use the
packages used with the put in pack functionality or a single package if
the user didn't use packages.
Once the order is purchased. It will post as message the tracking
links and the shipping labels.
"""
res = []
ep = EasypostRequest(self.sudo().easypost_production_api_key if self.prod_environment else self.sudo().easypost_test_api_key, self.log_xml)
for picking in pickings:
result = ep.send_shipping(self, picking.partner_id, picking.picking_type_id.warehouse_id.partner_id, picking=picking)
if result.get('error_message'):
raise UserError(result['error_message'])
rate = result.get('rate')
if rate['currency'] == picking.company_id.currency_id.name:
price = float(rate['rate'])
else:
quote_currency = self.env['res.currency'].search([('name', '=', rate['currency'])], limit=1)
price = quote_currency._convert(float(rate['rate']), picking.company_id.currency_id, self.env.company, fields.Date.context_today(self))
# Update price with the insurance cost
insurance_cost = result.get('insurance_cost', 0)
usd = self.env.ref('base.USD')
price += usd._convert(insurance_cost, picking.company_id.currency_id, self.env.company, fields.Date.context_today(self))
# return tracking information
carrier_tracking_link = ""
for track_number, tracker_url in result.get('track_shipments_url').items():
carrier_tracking_link += Markup("%s
") % (tracker_url, track_number)
carrier_tracking_ref = ' + '.join(result.get('track_shipments_url').keys())
# pickings where we should leave a lognote
lognote_pickings = picking.sale_id.picking_ids if picking.sale_id else picking
requests_session = requests.Session()
logmessage = Markup(_("Shipment created into Easypost
"
"Tracking Numbers: %s
")) % (carrier_tracking_link)
labels = []
for track_number, label_url in result.get('track_label_data').items():
try:
response = requests_session.get(label_url, timeout=30)
response.raise_for_status()
labels.append(('%s-%s.%s' % (self._get_delivery_label_prefix(), track_number, self.easypost_label_file_type), response.content))
except Exception:
logmessage += Markup('