summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRafi Zadanly <zadanlyr@gmail.com>2023-07-28 11:36:33 +0700
committerRafi Zadanly <zadanlyr@gmail.com>2023-07-28 11:36:33 +0700
commit71bdce1310997736f84a6d65d423fca801bfe655 (patch)
tree9001ee9f97d5abcd3214ea61ef12f78ff2b26f95
parenteacf53b314861bc797e1222d4b8d7ae9ef677040 (diff)
parentf26b2447f4f233a838e8990a800d975ab27a1557 (diff)
Merge branch 'aiway-bill' into development
-rw-r--r--indoteknik_api/controllers/api_v1/sale_order.py32
-rwxr-xr-xindoteknik_custom/__manifest__.py1
-rwxr-xr-xindoteknik_custom/models/__init__.py2
-rw-r--r--indoteknik_custom/models/airway_bill.py197
-rw-r--r--indoteknik_custom/models/airway_bill_manifest.py33
-rw-r--r--indoteknik_custom/models/stock_picking.py1
-rwxr-xr-xindoteknik_custom/security/ir.model.access.csv4
-rw-r--r--indoteknik_custom/views/airway_bill.xml105
8 files changed, 374 insertions, 1 deletions
diff --git a/indoteknik_api/controllers/api_v1/sale_order.py b/indoteknik_api/controllers/api_v1/sale_order.py
index a8b2fd11..cc7fd48f 100644
--- a/indoteknik_api/controllers/api_v1/sale_order.py
+++ b/indoteknik_api/controllers/api_v1/sale_order.py
@@ -372,7 +372,38 @@ class SaleOrder(controller.Controller):
'id': sale_order.id,
'name': sale_order.name
})
+
+ @http.route(PREFIX_PARTNER + 'sale-order/<id>/awb', auth='public', methods=['GET', 'OPTIONS'])
+ @controller.Controller.must_authorized(private=True, private_key='partner_id')
+ def get_airway_bill_by_sale_order_id(self, **kw):
+ id = int(kw.get('id', 0))
+ response = {'airways': None}
+ airway_bills = request.env['airway.bill'].search([('so_id', '=', id)])
+
+ if not airway_bills:
+ return self.response(response)
+
+ airways = []
+ for airway_bill in airway_bills:
+ data = airway_bill.decode_response()
+ delivery_order = airway_bill.do_id
+ result = data['rajaongkir']['result']
+ airways.append({
+ 'delivery_order': {
+ 'name': delivery_order.name,
+ 'carrier': delivery_order.carrier_id.name,
+ 'receiver_name': airway_bill.receiver_name,
+ 'receiver_city': airway_bill.receiver_city,
+ },
+ 'delivered': result['delivered'],
+ 'waybill_number': result['summary']['waybill_number'],
+ 'delivery_status': result['delivery_status'],
+ 'manifests': result['manifest']
+ })
+ response = {'airways': airways}
+ return self.response(response)
+
@http.route('/api/sale_order/invoiced', auth='public', methods=['GET'])
def get_sale_order_invoiced_by_partner_id(self, **kw):
if not self.authenticate():
@@ -481,3 +512,4 @@ class SaleOrder(controller.Controller):
}
return self.response(data)
+ \ No newline at end of file
diff --git a/indoteknik_custom/__manifest__.py b/indoteknik_custom/__manifest__.py
index dfe22fd2..91eb4166 100755
--- a/indoteknik_custom/__manifest__.py
+++ b/indoteknik_custom/__manifest__.py
@@ -85,6 +85,7 @@
'views/voucher.xml',
'views/bill_receipt.xml',
'views/account_move_multi_update.xml',
+ 'views/airway_bill.xml',
'report/report.xml',
'report/report_banner_banner.xml',
'report/report_banner_banner2.xml',
diff --git a/indoteknik_custom/models/__init__.py b/indoteknik_custom/models/__init__.py
index 5b8fcc54..54e24563 100755
--- a/indoteknik_custom/models/__init__.py
+++ b/indoteknik_custom/models/__init__.py
@@ -69,6 +69,8 @@ from . import manufacturing
from . import requisition
from . import token_storage
from . import product_sla
+from . import airway_bill
+from . import airway_bill_manifest
from . import account_move_due_extension
from . import voucher
from . import bill_receipt
diff --git a/indoteknik_custom/models/airway_bill.py b/indoteknik_custom/models/airway_bill.py
new file mode 100644
index 00000000..463272b4
--- /dev/null
+++ b/indoteknik_custom/models/airway_bill.py
@@ -0,0 +1,197 @@
+from odoo import models, fields
+from datetime import datetime, timedelta
+import logging
+import requests
+import json
+
+_logger = logging.getLogger(__name__)
+
+_key = '7ac9883688da043b50cc32f0e3070bb6'
+_url = 'https://pro.rajaongkir.com/api/waybill'
+
+class AirwayBill(models.Model):
+ _name = 'airway.bill'
+ _rec_name = 'number'
+
+ do_id = fields.Many2one('stock.picking', string='DO')
+ so_id = fields.Many2one('sale.order', string='SO')
+ number = fields.Char(string='Resi', help='Nomor Resi')
+ manifest_ids = fields.One2many('airway.bill.manifest', 'waybill_id', string='Airway Bill Lines', auto_join=True)
+ delivered = fields.Boolean(string='Delivered', help='terkirim atau belum / true or false')
+ response = fields.Char(string='Response', help='hasil history tracking dalam format json')
+ way_bill_date = fields.Char(string='Way Bill Date', compute='_compute_way_bill_datetime')
+ weight = fields.Char(string='Weight ', compute='_compute_way_bill_weight')
+ origin = fields.Char(string='Origin', compute='_compute_way_bill_origin')
+ destination = fields.Char(string='Destination', compute='_compute_way_bill_destination')
+ shipper_name = fields.Char(string='Shipper Name', compute='_compute_way_bill_shipper_name')
+ shipper_address1 = fields.Char(string='Shipper Address 1', compute='_compute_way_bill_shipper_address1')
+ shipper_address2 = fields.Char(string='Shipper Address 2', compute='_compute_way_bill_shipper_address2')
+ shipper_address3 = fields.Char(string='Shipper Address 3', compute='_compute_way_bill_shipper_address3')
+ shipper_city = fields.Char(string='Shipper City', compute='_compute_way_bill_shipper_city')
+ receiver_name = fields.Char(string='Receiver Name', compute='_compute_way_bill_receiver_name')
+ receiver_address1 = fields.Char(string='Receiver Address 1', compute='_compute_way_bill_receiver_address1')
+ receiver_address2 = fields.Char(string='Receiver Address 2', compute='_compute_way_bill_receiver_address2')
+ receiver_address3 = fields.Char(string='Receiver Address 3', compute='_compute_way_bill_receiver_address3')
+ receiver_city = fields.Char(string='Receiver City', compute='_compute_way_bill_receiver_city')
+ status = fields.Char(string='Status', compute='_compute_way_bill_status')
+ pod_receiver = fields.Char(string='Pod Receiver', compute='_compute_way_bill_pod_receiver')
+ pod_datetime = fields.Char(string='Pod Date', compute='_compute_way_bill_pod_datetime')
+
+ def decode_response(self):
+ self.ensure_one()
+ return self._json_decode(self.response)
+
+ def _fetch(self):
+ # jne, pos, tiki, wahana, jnt, rpx, sap, sicepat, jet, dse, dan first
+ carrier_ids = [51, 53, 54, 7, 57, 55, 59, 59, 27, 60, 62, 64]
+
+ delta_time = datetime.now() - timedelta(days=30) # Last 30 days
+ delta_time = delta_time.strftime('%Y-%m-%d %H:%M:%S')
+ query = [
+ '|',
+ ('waybill_id.delivered', '=', False),
+ ('date_done', '>', delta_time),
+ ('delivery_tracking_no', '!=', False),
+ ('delivery_tracking_no', 'not ilike', '-'),
+ ('carrier_id', 'in', carrier_ids),
+ ]
+ outs = self.env['stock.picking'].search(query, order='id')
+ for out in outs:
+ rajaongkir = self.env['rajaongkir.kurir'].search([('delivery_carrier_id', '=', out.carrier_id.id)])
+ history = self._get_waybill_history(out.delivery_tracking_no, rajaongkir.name)
+ if not history:
+ continue
+ delivered = history['rajaongkir']['result']['delivered']
+ values = {
+ 'do_id': out.id,
+ 'so_id': out.sale_id.id,
+ 'number': out.delivery_tracking_no,
+ 'delivered': delivered,
+ 'response': history,
+ }
+ waybill = out.waybill_id
+ if not waybill:
+ waybill = self.create(values)
+
+ waybill.response = json.dumps(history, indent=2, ensure_ascii=False)
+ waybill.manifest_ids.unlink()
+ self.env['airway.bill.manifest'].generate_airway_bill_line(waybill)
+
+ def _get_waybill_history(self, way_bill_number=0, shipper=0):
+ headers = {
+ 'content-type': 'application/x-www-form-urlencoded',
+ 'key': _key,
+ }
+
+ data = {
+ 'waybill': way_bill_number,
+ 'courier': shipper,
+ }
+
+ response = requests.post(_url, headers=headers, data=data)
+ return self._json_decode(response.text)
+
+ def _json_decode(self, content):
+ try:
+ response = json.loads(content)
+ return response
+ except:
+ return False
+
+ def _get_history(self, key):
+ response = self.decode_response()
+ if not response:
+ return response
+
+ if response.get('raja_ongkir', {}):
+ raja_ongkir = response.get('raja_ongkir', {})
+ elif response.get('rajaongkir', {}):
+ raja_ongkir = response.get('rajaongkir', {})
+ result = raja_ongkir.get('result', {})
+ return result.get(key)
+
+ def _compute_way_bill(self, airway, key, attribute):
+ details = airway._get_history('details')
+ delivery_status = airway._get_history('delivery_status')
+ value = None
+ if details and key in details:
+ value = details.get(key)
+ elif delivery_status and key in delivery_status:
+ value = delivery_status.get(key)
+ setattr(airway, attribute, value if value else '-')
+
+ def _compute_way_bill_datetime(self):
+ for airway in self:
+ self._compute_way_bill(airway, 'waybill_date', 'way_bill_date')
+
+ def _compute_way_bill_weight(self):
+ for airway in self:
+ self._compute_way_bill(airway, 'weight', 'weight')
+
+ def _compute_way_bill_origin(self):
+ for airway in self:
+ self._compute_way_bill(airway, 'origin', 'origin')
+
+ def _compute_way_bill_destination(self):
+ for airway in self:
+ self._compute_way_bill(airway, 'destination', 'destination')
+
+ def _compute_way_bill_shipper_name(self):
+ for airway in self:
+ self._compute_way_bill(airway, 'shippper_name', 'shipper_name')
+
+ def _compute_way_bill_shipper_address1(self):
+ for airway in self:
+ self._compute_way_bill(airway, 'shipper_address1', 'shipper_address1')
+
+ def _compute_way_bill_shipper_address2(self):
+ for airway in self:
+ self._compute_way_bill(airway, 'shipper_address2', 'shipper_address2')
+
+ def _compute_way_bill_shipper_address3(self):
+ for airway in self:
+ self._compute_way_bill(airway, 'shipper_address3', 'shipper_address3')
+
+ def _compute_way_bill_shipper_city(self):
+ for airway in self:
+ self._compute_way_bill(airway, 'shipper_city', 'shipper_city')
+
+ def _compute_way_bill_receiver_name(self):
+ for airway in self:
+ self._compute_way_bill(airway, 'receiver_name', 'receiver_name')
+
+ def _compute_way_bill_receiver_address1(self):
+ for airway in self:
+ self._compute_way_bill(airway, 'receiver_address1', 'receiver_address1')
+
+ def _compute_way_bill_receiver_address2(self):
+ for airway in self:
+ self._compute_way_bill(airway, 'receiver_address2', 'receiver_address2')
+
+ def _compute_way_bill_receiver_address3(self):
+ for airway in self:
+ self._compute_way_bill(airway, 'receiver_address3', 'receiver_address3')
+
+ def _compute_way_bill_receiver_city(self):
+ for airway in self:
+ self._compute_way_bill(airway, 'receiver_city', 'receiver_city')
+
+ def _compute_way_bill_status(self):
+ for airway in self:
+ self._compute_way_bill(airway, 'status', 'status')
+
+ def _compute_way_bill_pod_receiver(self):
+ for airway in self:
+ self._compute_way_bill(airway, 'pod_receiver', 'pod_receiver')
+
+ def _compute_way_bill_pod_datetime(self):
+ for airway in self:
+ details = airway._get_history('delivery_status')
+ if details:
+ pod_date = details['pod_date']
+ pod_time = details['pod_time']
+ airway.pod_datetime = pod_date+' '+pod_time
+ else:
+ airway.pod_datetime = '-'
+
+ \ No newline at end of file
diff --git a/indoteknik_custom/models/airway_bill_manifest.py b/indoteknik_custom/models/airway_bill_manifest.py
new file mode 100644
index 00000000..2e16be2c
--- /dev/null
+++ b/indoteknik_custom/models/airway_bill_manifest.py
@@ -0,0 +1,33 @@
+from odoo import models, fields
+import logging
+
+_logger = logging.getLogger(__name__)
+
+class AirwayBillManifest(models.Model):
+ _name = 'airway.bill.manifest'
+ _description = 'Airway B ill Line'
+ _order = 'waybill_id, id'
+
+ waybill_id = fields.Many2one('airway.bill', string='Airway Ref', required=True, ondelete='cascade', index=True, copy=False)
+ code = fields.Char('Code')
+ description = fields.Char('Description')
+ datetime = fields.Datetime('Datetime')
+ city = fields.Char('City')
+
+
+ def generate_airway_bill_line(self, waybill):
+ history = waybill.decode_response()
+ manifests = history['rajaongkir']['result']['manifest'] or []
+ for manifest in manifests:
+ code = manifest['manifest_code']
+ description = manifest['manifest_description']
+ date = manifest['manifest_date']
+ time = manifest['manifest_time']
+ city = manifest['city_name']
+ self.create({
+ 'waybill_id': waybill.id,
+ 'code': code,
+ 'description': description,
+ 'datetime': date+' '+time,
+ 'city': city,
+ }) \ No newline at end of file
diff --git a/indoteknik_custom/models/stock_picking.py b/indoteknik_custom/models/stock_picking.py
index 2ddb5f75..4d1df7ee 100644
--- a/indoteknik_custom/models/stock_picking.py
+++ b/indoteknik_custom/models/stock_picking.py
@@ -68,6 +68,7 @@ class StockPicking(models.Model):
('hold', 'Hold by Sales'),
('not_paid', 'Customer belum bayar')
], string='Note', help='jika field ini diisi maka tidak akan dihitung ke lead time')
+ waybill_id = fields.One2many(comodel_name='airway.bill', inverse_name='do_id', string='Airway Bill')
def action_create_invoice_from_mr(self):
"""Create the invoice associated to the PO.
diff --git a/indoteknik_custom/security/ir.model.access.csv b/indoteknik_custom/security/ir.model.access.csv
index 6e11bc5b..b3dce428 100755
--- a/indoteknik_custom/security/ir.model.access.csv
+++ b/indoteknik_custom/security/ir.model.access.csv
@@ -63,4 +63,6 @@ access_product_sla,access.product_sla,model_product_sla,,1,1,1,1
access_voucher,access.voucher,model_voucher,,1,1,1,1
access_bill_receipt,access.bill.receipt,model_bill_receipt,,1,1,1,1
access_bill_receipt_line,access.bill.receipt.line,model_bill_receipt_line,,1,1,1,1
-access_account_move_multi_update,access.account.move.multi_update,model_account_move_multi_update,,1,1,1,1 \ No newline at end of file
+access_account_move_multi_update,access.account.move.multi_update,model_account_move_multi_update,,1,1,1,1
+access_airway_bill,access.airway.bill,model_airway_bill,,1,1,1,1
+access_airway_bill_manifest,access.airway.bill.manifest,model_airway_bill_manifest,,1,1,1,1
diff --git a/indoteknik_custom/views/airway_bill.xml b/indoteknik_custom/views/airway_bill.xml
new file mode 100644
index 00000000..bbfd3991
--- /dev/null
+++ b/indoteknik_custom/views/airway_bill.xml
@@ -0,0 +1,105 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<odoo>
+ <record id="airway_bill_tree" model="ir.ui.view">
+ <field name="name">airway.bill.tree</field>
+ <field name="model">airway.bill</field>
+ <field name="arch" type="xml">
+ <tree>
+ <field name="number" />
+ <field name="so_id" />
+ <field name="do_id" />
+ <field name="delivered" />
+ </tree>
+ </field>
+ </record>
+
+ <record id="airway_bill_form" model="ir.ui.view">
+ <field name="name">airway.bill.form</field>
+ <field name="model">airway.bill</field>
+ <field name="arch" type="xml">
+ <form>
+ <sheet>
+ <group>
+ <group>
+ <field name="number" />
+ <field name="so_id" />
+ <field name="do_id" />
+ <field name="delivered" />
+ </group>
+ </group>
+ <notebook>
+ <page string="Airway Bill">
+ <field name="manifest_ids" readonly='1'>
+ <tree>
+ <field name="code"/>
+ <field name="description"/>
+ <field name="datetime"/>
+ <field name="city"/>
+ </tree>
+ </field>
+ </page>
+ <page string="Details">
+ <group>
+ <group string="Shipper">
+ <field name="shipper_name"/>
+ <field name="shipper_city"/>
+ <field name="shipper_address1"/>
+ <field name="shipper_address2"/>
+ <field name="shipper_address3"/>
+ </group>
+ <group string="Receiver">
+ <field name="receiver_name"/>
+ <field name="receiver_city"/>
+ <field name="receiver_address1"/>
+ <field name="receiver_address2"/>
+ <field name="receiver_address3"/>
+ </group>
+ <group string="Other Info">
+ <field name="way_bill_date"/>
+ <field name="weight"/>
+ <field name="origin"/>
+ <field name="destination"/>
+ </group>
+ </group>
+ </page>
+ <page string="Delivery Status">
+ <group>
+ <group>
+ <field name="status"/>
+ <field name="pod_receiver"/>
+ <field name="pod_datetime"/>
+ </group>
+ </group>
+ </page>
+ </notebook>
+ </sheet>
+ </form>
+ </field>
+ </record>
+
+ <record id="airway_bill_action" model="ir.actions.act_window">
+ <field name="name">Airway Bill</field>
+ <field name="type">ir.actions.act_window</field>
+ <field name="res_model">airway.bill</field>
+ <field name="view_mode">tree,form</field>
+ </record>
+
+ <record id="cron_airway_bill_fetch" model="ir.cron">
+ <field name="name">Airway Bill: Fetch</field>
+ <field name="interval_number">1</field>
+ <field name="interval_type">days</field>
+ <field name="numbercall">-1</field>
+ <field name="doall" eval="False"/>
+ <field name="model_id" ref="model_airway_bill"/>
+ <field name="code">model._fetch()</field>
+ <field name="state">code</field>
+ <field name="priority">75</field>
+ <field name="active">True</field>
+ </record>
+
+ <menuitem id="menu_airway_bill"
+ name="Airway Bill"
+ action="airway_bill_action"
+ parent="stock.menu_stock_warehouse_mgmt"
+ sequence="200"/>
+</odoo> \ No newline at end of file