diff options
| -rwxr-xr-x | indoteknik_custom/models/sale_order.py | 4 | ||||
| -rw-r--r-- | indoteknik_custom/models/stock_picking.py | 73 |
2 files changed, 49 insertions, 28 deletions
diff --git a/indoteknik_custom/models/sale_order.py b/indoteknik_custom/models/sale_order.py index f2bb27ad..a4166016 100755 --- a/indoteknik_custom/models/sale_order.py +++ b/indoteknik_custom/models/sale_order.py @@ -862,8 +862,8 @@ class SaleOrder(models.Model): def _call_biteship_api(self, origin_data, destination_data, items, couriers=None): - url = 'https://api.biteship.com/v1/rates/couriers' - api_key = 'biteship_test.eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYW1lIjoiSW5kb3Rla25payIsInVzZXJJZCI6IjY3MTViYTJkYzVkMjdkMDAxMjRjODk2MiIsImlhdCI6MTcyOTQ5ODAwMX0.L6C73couP4-cgVEfhKI2g7eMCMo3YOFSRZhS-KSuHNA' + url = "https://api.biteship.com/v1/rates/couriers" + api_key = "biteship_test.eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYW1lIjoiSW5kb3Rla25payIsInVzZXJJZCI6IjY3MTViYTJkYzVkMjdkMDAxMjRjODk2MiIsImlhdCI6MTcyOTQ5ODAwMX0.L6C73couP4-cgVEfhKI2g7eMCMo3YOFSRZhS-KSuHNA" headers = { 'Authorization': api_key, diff --git a/indoteknik_custom/models/stock_picking.py b/indoteknik_custom/models/stock_picking.py index 4522dac0..54da700b 100644 --- a/indoteknik_custom/models/stock_picking.py +++ b/indoteknik_custom/models/stock_picking.py @@ -526,46 +526,55 @@ class StockPicking(models.Model): if self.biteship_tracking_id: raise UserError(f"Order ini sudah dikirim ke Biteship. Dengan Tracking Id: {self.biteship_tracking_id}") - # Mencari data sale.order.line berdasarkan sale_id + # Fungsi bantu: menentukan apakah kurir perlu koordinat + def is_courier_need_coordinates(service_code): + return service_code in [ + "instant", "same_day", "instant_car", + "instant_bike", "motorcycle", "mpv", "van", "truck", + "cdd_bak", "cdd_box", "engkel_box", "engkel_bak" + ] + + # Ambil order line products = self.env['sale.order.line'].search([('order_id', '=', self.sale_id.id)]) - - # Fungsi untuk membangun items_data dari order lines + + # Bangun data items untuk standard def build_items_data(lines): return [{ "name": line.product_id.name, "description": line.name, "value": line.price_unit, "quantity": line.product_uom_qty, - "weight": line.weight + "weight": line.weight*1000 } for line in lines] - # Items untuk pengiriman standard items_data_standard = build_items_data(products) - # Items untuk pengiriman instant, mengambil product_id dari move_line_ids_without_package + # Bangun data items untuk pengiriman instant items_data_instant = [] for move_line in self.move_line_ids_without_package: - # Mencari baris di sale.order.line berdasarkan product_id dari move_line order_line = self.env['sale.order.line'].search([ ('order_id', '=', self.sale_id.id), ('product_id', '=', move_line.product_id.id) ], limit=1) - + if order_line: items_data_instant.append({ "name": order_line.product_id.name, "description": order_line.name, "value": order_line.price_unit, "quantity": move_line.qty_done, - "weight": order_line.weight + "weight": order_line.weight*1000 }) + _logger.info(f"Items data standard: {items_data_standard}") + _logger.info(f"Items data instant: {items_data_instant}") + # Bangun payload dasar payload = { - "origin_coordinate" :{ + "origin_coordinate": { "latitude": -6.3031123, - "longitude" : 106.7794934999 + "longitude": 106.7794934999 }, - "reference_id" : self.sale_id.name, + "reference_id": self.sale_id.name, "shipper_contact_name": self.carrier_id.pic_name or '', "shipper_contact_phone": self.carrier_id.pic_phone or '', "shipper_organization": self.carrier_id.name, @@ -581,30 +590,40 @@ class StockPicking(models.Model): "courier_type": self.sale_id.delivery_service_type or "reg", "courier_company": self.carrier_id.name.lower(), "delivery_type": "now", - "destination_postal_code": self.real_shipping_id.zip, "items": items_data_standard } - _logger.info(f"Payload untuk Biteship: {payload}") + _logger.info(f"Delivery service type: {self.sale_id.delivery_service_type}") + _logger.info(f"Carrier: {self.carrier_id.name}") + _logger.info(f"Payload awal: {payload}") + + # Tambahkan destination_coordinate jika diperlukan + if is_courier_need_coordinates(self.sale_id.delivery_service_type): + if not self.real_shipping_id.latitude or not self.real_shipping_id.longtitude: + raise UserError("Alamat tujuan tidak memiliki koordinat (latitude/longitude).") + + # items_to_use = items_data_instant if items_data_instant else items_data_standard + if not items_data_instant: + raise UserError("Pengiriman instant membutuhkan produk yang sudah diproses (qty_done > 0). Harap lakukan validasi picking terlebih dahulu.") - # Cek jika pengiriman instant atau same_day - if self.sale_id.delivery_service_type and ("instant" in self.sale_id.delivery_service_type or "same_day" in self.sale_id.delivery_service_type): payload.update({ - "destination_coordinate" : { + "destination_coordinate": { "latitude": self.real_shipping_id.latitude, "longitude": self.real_shipping_id.longtitude, }, "items": items_data_instant }) - + + _logger.info(f"Payload untuk Biteship: {payload}") + + # Kirim ke Biteship api_key = _biteship_api_key headers = { "Authorization": f"Bearer {api_key}", "Content-Type": "application/json" } - # Kirim request ke Biteship - response = requests.post(_biteship_url+'/orders', headers=headers, json=payload) + response = requests.post(_biteship_url + '/orders', headers=headers, json=payload) _logger.info(f"Response dari Biteship: {response.text}") if response.status_code == 200: @@ -614,11 +633,11 @@ class StockPicking(models.Model): self.biteship_tracking_id = data.get("courier", {}).get("tracking_id", "") self.biteship_waybill_id = data.get("courier", {}).get("waybill_id", "") self.delivery_tracking_no = data.get("courier", {}).get("waybill_id", "") - - waybill_id = data.get("courier", {}).get("waybill_id", "") + + waybill_id = self.biteship_waybill_id self.message_post( - body=f"📦 Biteship berhasil dilakukan.<br/>" + body=f"Biteship berhasil dilakukan.<br/>" f"Kurir: {self.carrier_id.name}<br/>" f"Tracking ID: {self.biteship_tracking_id or '-'}<br/>" f"Resi: {waybill_id or '-'}", @@ -629,16 +648,18 @@ class StockPicking(models.Model): return { 'effect': { - 'fadeout': 'slow', # Efek menghilang perlahan - 'message': message, # Pesan sukses - 'type': 'rainbow_man', # Efek animasi lucu Odoo + 'fadeout': 'slow', + 'message': message, + 'type': 'rainbow_man', } } + else: error_data = response.json() error_message = error_data.get("error", "Unknown error") error_code = error_data.get("code", "No code provided") raise UserError(f"Error saat mengirim ke Biteship: {error_message} (Code: {error_code})") + @api.constrains('driver_departure_date') def constrains_driver_departure_date(self): |
