From 3ca53ea0afef07cb79040c9f3c5aa29fa2355c90 Mon Sep 17 00:00:00 2001 From: trisusilo48 Date: Thu, 27 Mar 2025 08:48:27 +0700 Subject: sale order delay --- indoteknik_custom/models/stock_picking.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'indoteknik_custom/models/stock_picking.py') diff --git a/indoteknik_custom/models/stock_picking.py b/indoteknik_custom/models/stock_picking.py index 6c6cbaa1..a11bf29f 100644 --- a/indoteknik_custom/models/stock_picking.py +++ b/indoteknik_custom/models/stock_picking.py @@ -16,8 +16,8 @@ import re _logger = logging.getLogger(__name__) _biteship_url = "https://api.biteship.com/v1" -_biteship_api_key = "biteship_test.eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYW1lIjoiSW5kb3Rla25payIsInVzZXJJZCI6IjY3MTViYTJkYzVkMjdkMDAxMjRjODk2MiIsImlhdCI6MTcyOTQ5ODAwMX0.L6C73couP4-cgVEfhKI2g7eMCMo3YOFSRZhS-KSuHNA" -# _biteship_api_key = "biteship_live.eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYW1lIjoiaW5kb3Rla25payIsInVzZXJJZCI6IjY3MTViYTJkYzVkMjdkMDAxMjRjODk2MiIsImlhdCI6MTc0MTE1NTU4M30.pbFCai9QJv8iWhgdosf8ScVmEeP3e5blrn33CHe7Hgo" +# _biteship_api_key = "biteship_test.eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYW1lIjoiSW5kb3Rla25payIsInVzZXJJZCI6IjY3MTViYTJkYzVkMjdkMDAxMjRjODk2MiIsImlhdCI6MTcyOTQ5ODAwMX0.L6C73couP4-cgVEfhKI2g7eMCMo3YOFSRZhS-KSuHNA" +_biteship_api_key = "biteship_live.eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYW1lIjoiaW5kb3Rla25payIsInVzZXJJZCI6IjY3MTViYTJkYzVkMjdkMDAxMjRjODk2MiIsImlhdCI6MTc0MTE1NTU4M30.pbFCai9QJv8iWhgdosf8ScVmEeP3e5blrn33CHe7Hgo" @@ -1241,7 +1241,7 @@ class StockPicking(models.Model): 'confirmed' : 'Indoteknik telah melakukan permintaan pick-up', 'allocated' : 'Kurir akan melakukan pick-up pesanan', 'picking_up' : 'Kurir sedang dalam perjalanan menuju lokasi pick-up', - 'picked' : 'Pesanan sudah di pick-up kurir '+result.get("courier", {}).get("name", ""), + 'picked' : 'Pesanan sudah di pick-up kurir '+result.get("courier", {}).get("company", ""), 'on_hold' : 'Pesanan ditahan sementara karena masalah pengiriman', 'dropping_off' : 'Kurir sudah ditugaskan dan pesanan akan segera diantar ke pembeli', 'delivered' : 'Pesanan telah sampai dan diterima oleh '+result.get("destination", {}).get("contact_name", "") -- cgit v1.2.3 From 337e86c31691544a49a04e3f8d3a4b259e6b126a Mon Sep 17 00:00:00 2001 From: trisusilo48 Date: Thu, 10 Apr 2025 08:51:12 +0700 Subject: testing biteship dinamis eta --- indoteknik_custom/models/stock_picking.py | 91 +++++++++++-------------------- 1 file changed, 33 insertions(+), 58 deletions(-) (limited to 'indoteknik_custom/models/stock_picking.py') diff --git a/indoteknik_custom/models/stock_picking.py b/indoteknik_custom/models/stock_picking.py index a11bf29f..b741e94e 100644 --- a/indoteknik_custom/models/stock_picking.py +++ b/indoteknik_custom/models/stock_picking.py @@ -16,8 +16,8 @@ import re _logger = logging.getLogger(__name__) _biteship_url = "https://api.biteship.com/v1" -# _biteship_api_key = "biteship_test.eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYW1lIjoiSW5kb3Rla25payIsInVzZXJJZCI6IjY3MTViYTJkYzVkMjdkMDAxMjRjODk2MiIsImlhdCI6MTcyOTQ5ODAwMX0.L6C73couP4-cgVEfhKI2g7eMCMo3YOFSRZhS-KSuHNA" -_biteship_api_key = "biteship_live.eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYW1lIjoiaW5kb3Rla25payIsInVzZXJJZCI6IjY3MTViYTJkYzVkMjdkMDAxMjRjODk2MiIsImlhdCI6MTc0MTE1NTU4M30.pbFCai9QJv8iWhgdosf8ScVmEeP3e5blrn33CHe7Hgo" +_biteship_api_key = "biteship_test.eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYW1lIjoiSW5kb3Rla25payIsInVzZXJJZCI6IjY3MTViYTJkYzVkMjdkMDAxMjRjODk2MiIsImlhdCI6MTcyOTQ5ODAwMX0.L6C73couP4-cgVEfhKI2g7eMCMo3YOFSRZhS-KSuHNA" +# _biteship_api_key = "biteship_live.eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYW1lIjoiaW5kb3Rla25payIsInVzZXJJZCI6IjY3MTViYTJkYzVkMjdkMDAxMjRjODk2MiIsImlhdCI6MTc0MTE1NTU4M30.pbFCai9QJv8iWhgdosf8ScVmEeP3e5blrn33CHe7Hgo" @@ -189,63 +189,12 @@ class StockPicking(models.Model): biteship_id = fields.Char(string="Biteship Respon ID") biteship_tracking_id = fields.Char(string="Biteship Trackcking ID") biteship_waybill_id = fields.Char(string="Biteship Waybill ID") - # estimated_ready_ship_date = fields.Datetime(string='ET Ready to Ship', copy=False, related='sale_id.estimated_ready_ship_date') - # countdown_hours = fields.Float(string='Countdown in Hours', compute='_callculate_sequance', default=False, store=False, compute_sudo=False) - # countdown_ready_to_ship = fields.Char(string='Countdown Ready to Ship', compute='_callculate_sequance', store=False, compute_sudo=False) final_seq = fields.Float(string='Remaining Time') def schduled_update_sequance(self): query = "SELECT update_sequance_stock_picking();" self.env.cr.execute(query) - - - # @api.depends('estimated_ready_ship_date', 'state') - # def _callculate_sequance(self): - # for record in self: - # try : - # if record.estimated_ready_ship_date and record.state not in ('cancel', 'done'): - # rts = record.estimated_ready_ship_date - waktu.now() - # rts_days = rts.days - # rts_hours = divmod(rts.seconds, 3600) - - # estimated_by_erts = rts.total_seconds() / 3600 - - # record.countdown_ready_to_ship = f"{rts_days} days, {rts_hours} hours" - # record.countdown_hours = estimated_by_erts - # else: - # record.countdown_hours = 999999999999 - # record.countdown_ready_to_ship = False - # except Exception as e : - # _logger.error(f"Error calculating sequance {record.id}: {str(e)}") - # print(str(e)) - # return { 'error': str(e) } - - - # @api.depends('estimated_ready_ship_date', 'state') - # def _compute_countdown_hours(self): - # for record in self: - # if record.state in ('cancel', 'done') or not record.estimated_ready_ship_date: - # # Gunakan nilai yang sangat besar sebagai placeholder - # record.countdown_hours = 999999 - # else: - # delta = record.estimated_ready_ship_date - waktu.now() - # record.countdown_hours = delta.total_seconds() / 3600 - - # @api.depends('estimated_ready_ship_date', 'state') - # def _compute_countdown_ready_to_ship(self): - # for record in self: - # if record.state in ('cancel', 'done'): - # record.countdown_ready_to_ship = False - # else: - # if record.estimated_ready_ship_date: - # delta = record.estimated_ready_ship_date - waktu.now() - # days = delta.days - # hours, remainder = divmod(delta.seconds, 3600) - # record.countdown_ready_to_ship = f"{days} days, {hours} hours" - # record.countdown_hours = delta.total_seconds() / 3600 - # else: - # record.countdown_ready_to_ship = False def _compute_lalamove_image_html(self): for record in self: @@ -1182,6 +1131,8 @@ class StockPicking(models.Model): self.ensure_one() order = self.env['sale.order'].search([('name', '=', self.sale_id.name)], limit=1) + + sale_order_delay = self.env['sale.order.delay'].search([('so_number', '=', order.name)], limit=1) response = { 'delivery_order': { @@ -1197,13 +1148,24 @@ class StockPicking(models.Model): 'delivery_status': None, 'eta': self.generate_eta_delivery(), 'is_biteship': True if self.biteship_id else False, - 'manifests': self.get_manifests() + 'manifests': self.get_manifests(), + 'is_delay': True if sale_order_delay and sale_order_delay.status == 'delayed' else False } if self.biteship_id : histori = self.get_manifest_biteship() - eta_start = order.date_order + timedelta(days=order.estimated_arrival_days_start) - eta_end = order.date_order + timedelta(days=order.estimated_arrival_days) + day_start = order.estomated_arrival_days_start + day_end = order.estomated_arrival_days + if sale_order_delay: + if sale_order_delay.status == 'delayed': + day_start = day_start + sale_order_delay.days_delayed + day_end = day_end + sale_order_delay.days_delayed + elif sale_order_delay.status == 'early': + day_start = day_start - sale_order_delay.days_delayed + day_end = day_end - sale_order_delay.days_delayed + + eta_start = order.date_order + timedelta(days=day_start) + eta_end = order.date_order + timedelta(days=day_end) formatted_eta = f"{eta_start.strftime('%d %b')} - {eta_end.strftime('%d %b %Y')}" response['eta'] = formatted_eta response['manifests'] = histori.get("manifests", []) @@ -1297,18 +1259,31 @@ class StockPicking(models.Model): current_date = datetime.datetime.now() prepare_days = 3 start_date = self.driver_departure_date or self.create_date + + + add_day_start = 0 + add_day_end = 0 + sale_order_delay = self.env['sale.order.delay'].search([('so_number', '=', self.sale_id.name)], limit=1) + if sale_order_delay: + if sale_order_delay.status == 'delayed': + add_day_start = sale_order_delay.days_delayed + add_day_end = sale_order_delay.days_delayed + elif sale_order_delay.status == 'early': + add_day_start = -abs(sale_order_delay.days_delayed) + add_day_end = -abs(sale_order_delay.days_delayed) ead = self.sale_id.estimated_arrival_days or 0 if not self.driver_departure_date: ead += prepare_days ead_datetime = datetime.timedelta(days=ead) - fastest_eta = start_date + ead_datetime + fastest_eta = start_date + ead_datetime + datetime.timedelta(days=add_day_start) + if not self.driver_departure_date and fastest_eta < current_date: fastest_eta = current_date + ead_datetime longest_days = 3 - longest_eta = fastest_eta + datetime.timedelta(days=longest_days) + longest_eta = fastest_eta + datetime.timedelta(days=longest_days + add_day_end) format_time = '%d %b %Y' format_time_fastest = '%d %b' if fastest_eta.year == longest_eta.year else format_time -- cgit v1.2.3 From 62f9c93c02a1f8b12ecd7bf50f850c43dd7c2c49 Mon Sep 17 00:00:00 2001 From: trisusilo48 Date: Fri, 11 Apr 2025 10:14:08 +0700 Subject: dirver departure date --- indoteknik_custom/models/stock_picking.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'indoteknik_custom/models/stock_picking.py') diff --git a/indoteknik_custom/models/stock_picking.py b/indoteknik_custom/models/stock_picking.py index b741e94e..d7e8e0e8 100644 --- a/indoteknik_custom/models/stock_picking.py +++ b/indoteknik_custom/models/stock_picking.py @@ -16,8 +16,8 @@ import re _logger = logging.getLogger(__name__) _biteship_url = "https://api.biteship.com/v1" -_biteship_api_key = "biteship_test.eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYW1lIjoiSW5kb3Rla25payIsInVzZXJJZCI6IjY3MTViYTJkYzVkMjdkMDAxMjRjODk2MiIsImlhdCI6MTcyOTQ5ODAwMX0.L6C73couP4-cgVEfhKI2g7eMCMo3YOFSRZhS-KSuHNA" -# _biteship_api_key = "biteship_live.eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYW1lIjoiaW5kb3Rla25payIsInVzZXJJZCI6IjY3MTViYTJkYzVkMjdkMDAxMjRjODk2MiIsImlhdCI6MTc0MTE1NTU4M30.pbFCai9QJv8iWhgdosf8ScVmEeP3e5blrn33CHe7Hgo" +# _biteship_api_key = "biteship_test.eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYW1lIjoiSW5kb3Rla25payIsInVzZXJJZCI6IjY3MTViYTJkYzVkMjdkMDAxMjRjODk2MiIsImlhdCI6MTcyOTQ5ODAwMX0.L6C73couP4-cgVEfhKI2g7eMCMo3YOFSRZhS-KSuHNA" +_biteship_api_key = "biteship_live.eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYW1lIjoiaW5kb3Rla25payIsInVzZXJJZCI6IjY3MTViYTJkYzVkMjdkMDAxMjRjODk2MiIsImlhdCI6MTc0MTE1NTU4M30.pbFCai9QJv8iWhgdosf8ScVmEeP3e5blrn33CHe7Hgo" @@ -1142,6 +1142,7 @@ class StockPicking(models.Model): 'receiver_name': '', 'receiver_city': '' }, + 'delivered_date': self.driver_departure_date or False, 'delivered': False, 'status': self.shipping_status, 'waybill_number': self.delivery_tracking_no or '', @@ -1154,8 +1155,8 @@ class StockPicking(models.Model): if self.biteship_id : histori = self.get_manifest_biteship() - day_start = order.estomated_arrival_days_start - day_end = order.estomated_arrival_days + day_start = order.estimated_arrival_days_start + day_end = order.estimated_arrival_days if sale_order_delay: if sale_order_delay.status == 'delayed': day_start = day_start + sale_order_delay.days_delayed @@ -1192,7 +1193,6 @@ class StockPicking(models.Model): "Content-Type": "application/json" } - manifests = [] try: @@ -1206,7 +1206,7 @@ class StockPicking(models.Model): 'picked' : 'Pesanan sudah di pick-up kurir '+result.get("courier", {}).get("company", ""), 'on_hold' : 'Pesanan ditahan sementara karena masalah pengiriman', 'dropping_off' : 'Kurir sudah ditugaskan dan pesanan akan segera diantar ke pembeli', - 'delivered' : 'Pesanan telah sampai dan diterima oleh '+result.get("destination", {}).get("contact_name", "") + 'delivered' : f'Pesanan telah sampai dan diterima oleh {result.get("destination", {}).get("contact_name", "")}' } if(result.get('success') == True): history = result.get("history", []) -- cgit v1.2.3 From ef00237c7b6b3aed4f6040d1f124199d3551561e Mon Sep 17 00:00:00 2001 From: trisusilo48 Date: Fri, 11 Apr 2025 14:50:53 +0700 Subject: expected delivery date manifest --- indoteknik_custom/models/stock_picking.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'indoteknik_custom/models/stock_picking.py') diff --git a/indoteknik_custom/models/stock_picking.py b/indoteknik_custom/models/stock_picking.py index d7e8e0e8..54256299 100644 --- a/indoteknik_custom/models/stock_picking.py +++ b/indoteknik_custom/models/stock_picking.py @@ -1137,15 +1137,15 @@ class StockPicking(models.Model): response = { 'delivery_order': { 'name': self.name, - 'carrier': self.carrier_id.name or '', - 'service' : order.delivery_service_type or '', + 'carrier': self.carrier_id.name or '-', + 'service' : order.delivery_service_type or '-', 'receiver_name': '', 'receiver_city': '' }, - 'delivered_date': self.driver_departure_date or False, + 'delivered_date': self.driver_departure_date.strftime('%d %b %Y') if self.driver_departure_date != False else '-', 'delivered': False, 'status': self.shipping_status, - 'waybill_number': self.delivery_tracking_no or '', + 'waybill_number': self.delivery_tracking_no or '-', 'delivery_status': None, 'eta': self.generate_eta_delivery(), 'is_biteship': True if self.biteship_id else False, @@ -1205,7 +1205,7 @@ class StockPicking(models.Model): 'picking_up' : 'Kurir sedang dalam perjalanan menuju lokasi pick-up', 'picked' : 'Pesanan sudah di pick-up kurir '+result.get("courier", {}).get("company", ""), 'on_hold' : 'Pesanan ditahan sementara karena masalah pengiriman', - 'dropping_off' : 'Kurir sudah ditugaskan dan pesanan akan segera diantar ke pembeli', + 'dropping_off' : 'Kurir sudah ditugaskan dan pesanan akan segera diantar ke pembeli', 'delivered' : f'Pesanan telah sampai dan diterima oleh {result.get("destination", {}).get("contact_name", "")}' } if(result.get('success') == True): -- cgit v1.2.3 From 6eb0b48ad5c418f565efdf1a60d221a10465b0b8 Mon Sep 17 00:00:00 2001 From: trisusilo48 Date: Mon, 14 Apr 2025 16:48:09 +0700 Subject: stock picking mapping --- indoteknik_custom/models/stock_picking.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'indoteknik_custom/models/stock_picking.py') diff --git a/indoteknik_custom/models/stock_picking.py b/indoteknik_custom/models/stock_picking.py index 54256299..ba7a9452 100644 --- a/indoteknik_custom/models/stock_picking.py +++ b/indoteknik_custom/models/stock_picking.py @@ -16,8 +16,8 @@ import re _logger = logging.getLogger(__name__) _biteship_url = "https://api.biteship.com/v1" -# _biteship_api_key = "biteship_test.eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYW1lIjoiSW5kb3Rla25payIsInVzZXJJZCI6IjY3MTViYTJkYzVkMjdkMDAxMjRjODk2MiIsImlhdCI6MTcyOTQ5ODAwMX0.L6C73couP4-cgVEfhKI2g7eMCMo3YOFSRZhS-KSuHNA" -_biteship_api_key = "biteship_live.eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYW1lIjoiaW5kb3Rla25payIsInVzZXJJZCI6IjY3MTViYTJkYzVkMjdkMDAxMjRjODk2MiIsImlhdCI6MTc0MTE1NTU4M30.pbFCai9QJv8iWhgdosf8ScVmEeP3e5blrn33CHe7Hgo" +_biteship_api_key = "biteship_test.eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYW1lIjoiSW5kb3Rla25payIsInVzZXJJZCI6IjY3MTViYTJkYzVkMjdkMDAxMjRjODk2MiIsImlhdCI6MTcyOTQ5ODAwMX0.L6C73couP4-cgVEfhKI2g7eMCMo3YOFSRZhS-KSuHNA" +# _biteship_api_key = "biteship_live.eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYW1lIjoiaW5kb3Rla25payIsInVzZXJJZCI6IjY3MTViYTJkYzVkMjdkMDAxMjRjODk2MiIsImlhdCI6MTc0MTE1NTU4M30.pbFCai9QJv8iWhgdosf8ScVmEeP3e5blrn33CHe7Hgo" -- cgit v1.2.3 From fb50d10576f2e5d16faba612dfd1565f7168f655 Mon Sep 17 00:00:00 2001 From: trisusilo48 Date: Wed, 16 Apr 2025 14:33:31 +0700 Subject: FEEDBACK --- indoteknik_custom/models/stock_picking.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'indoteknik_custom/models/stock_picking.py') diff --git a/indoteknik_custom/models/stock_picking.py b/indoteknik_custom/models/stock_picking.py index 4a200ac5..f2b69b55 100644 --- a/indoteknik_custom/models/stock_picking.py +++ b/indoteknik_custom/models/stock_picking.py @@ -1406,7 +1406,10 @@ class StockPicking(models.Model): "delivered": status } - return manifests + return { + "manifests": [], + "delivered": False + } except Exception as e : _logger.error(f"Error fetching Biteship order for picking {self.id}: {str(e)}") return { 'error': str(e) } -- cgit v1.2.3 From d9d8b9f3afc0ad60ca1199b08ab6e2836663a0de Mon Sep 17 00:00:00 2001 From: trisusilo48 Date: Thu, 24 Apr 2025 13:54:06 +0700 Subject: fixing revisi renca --- indoteknik_custom/models/stock_picking.py | 19 ++++++------------- 1 file changed, 6 insertions(+), 13 deletions(-) (limited to 'indoteknik_custom/models/stock_picking.py') diff --git a/indoteknik_custom/models/stock_picking.py b/indoteknik_custom/models/stock_picking.py index f2b69b55..aa616e62 100644 --- a/indoteknik_custom/models/stock_picking.py +++ b/indoteknik_custom/models/stock_picking.py @@ -1442,8 +1442,10 @@ class StockPicking(models.Model): def generate_eta_delivery(self): current_date = datetime.datetime.now() - prepare_days = 3 - start_date = self.driver_departure_date or self.create_date + days_start = self.sale_id.estimated_arrival_days_start or self.sale_id.estimated_arrival_days + days_end = self.sale_id.estimated_arrival_days or (self.sale_id.estimated_arrival_days + 3) + start_date = self.sale_id.create_date + datetime.timedelta(days=days_start) + end_date = self.sale_id.create_date + datetime.timedelta(days=days_end) add_day_start = 0 @@ -1456,19 +1458,10 @@ class StockPicking(models.Model): elif sale_order_delay.status == 'early': add_day_start = -abs(sale_order_delay.days_delayed) add_day_end = -abs(sale_order_delay.days_delayed) - - ead = self.sale_id.estimated_arrival_days or 0 - if not self.driver_departure_date: - ead += prepare_days - - ead_datetime = datetime.timedelta(days=ead) - fastest_eta = start_date + ead_datetime + datetime.timedelta(days=add_day_start) - if not self.driver_departure_date and fastest_eta < current_date: - fastest_eta = current_date + ead_datetime + fastest_eta = start_date +datetime.timedelta(days=add_day_start + add_day_start) - longest_days = 3 - longest_eta = fastest_eta + datetime.timedelta(days=longest_days + add_day_end) + longest_eta = end_date + datetime.timedelta(days=add_day_end) format_time = '%d %b %Y' format_time_fastest = '%d %b' if fastest_eta.year == longest_eta.year else format_time -- cgit v1.2.3 From 914705630f61f2e02f15ee24a479191e945a0f22 Mon Sep 17 00:00:00 2001 From: trisusilo48 Date: Sat, 26 Apr 2025 08:39:32 +0700 Subject: handle bugs additional time when checkout > 15.00 --- indoteknik_custom/models/stock_picking.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'indoteknik_custom/models/stock_picking.py') diff --git a/indoteknik_custom/models/stock_picking.py b/indoteknik_custom/models/stock_picking.py index 36129f00..38a1173c 100644 --- a/indoteknik_custom/models/stock_picking.py +++ b/indoteknik_custom/models/stock_picking.py @@ -562,6 +562,10 @@ class StockPicking(models.Model): }) payload = { + "origin_coordinate" :{ + "latitude": -6.3031123, + "longitude" : 106.7794934999 + }, "reference_id " : self.sale_id.name, "shipper_contact_name": self.carrier_id.pic_name or '', "shipper_contact_phone": self.carrier_id.pic_phone or '', @@ -585,10 +589,6 @@ class StockPicking(models.Model): # 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({ - "origin_coordinate" :{ - "latitude": -6.3031123, - "longitude" : 106.7794934999 - }, "destination_coordinate" : { "latitude": self.real_shipping_id.latitude, "longitude": self.real_shipping_id.longtitude, -- cgit v1.2.3 From 509eb9406e6c48caf3e6366c3d8ac60643b71546 Mon Sep 17 00:00:00 2001 From: trisusilo48 Date: Tue, 29 Apr 2025 09:09:05 +0700 Subject: fixing jam 15 --- indoteknik_custom/models/stock_picking.py | 1 - 1 file changed, 1 deletion(-) (limited to 'indoteknik_custom/models/stock_picking.py') diff --git a/indoteknik_custom/models/stock_picking.py b/indoteknik_custom/models/stock_picking.py index 38a1173c..39c74aa2 100644 --- a/indoteknik_custom/models/stock_picking.py +++ b/indoteknik_custom/models/stock_picking.py @@ -523,7 +523,6 @@ class StockPicking(models.Model): raise UserError(f"Kesalahan tidak terduga: {str(e)}") def action_send_to_biteship(self): - if self.biteship_tracking_id: raise UserError(f"Order ini sudah dikirim ke Biteship. Dengan Tracking Id: {self.biteship_tracking_id}") -- cgit v1.2.3 From fad209db285b0a6204dc1fcbf2e2e0cb13f872b0 Mon Sep 17 00:00:00 2001 From: "Indoteknik ." Date: Fri, 23 May 2025 09:05:27 +0700 Subject: (andri) penyesuaian data quotation SO ke delivery biteship --- indoteknik_custom/models/stock_picking.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'indoteknik_custom/models/stock_picking.py') diff --git a/indoteknik_custom/models/stock_picking.py b/indoteknik_custom/models/stock_picking.py index 39c74aa2..5548db75 100644 --- a/indoteknik_custom/models/stock_picking.py +++ b/indoteknik_custom/models/stock_picking.py @@ -565,7 +565,7 @@ class StockPicking(models.Model): "latitude": -6.3031123, "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, @@ -585,6 +585,8 @@ class StockPicking(models.Model): "items": items_data_standard } + _logger.info(f"Payload untuk Biteship: {payload}") + # 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({ @@ -603,6 +605,7 @@ class StockPicking(models.Model): # Kirim request ke Biteship response = requests.post(_biteship_url+'/orders', headers=headers, json=payload) + _logger.info(f"Response dari Biteship: {response.text}") if response.status_code == 200: data = response.json() -- cgit v1.2.3 From 4ed94e9e1de027aba326ff3dce954b765f752009 Mon Sep 17 00:00:00 2001 From: "Indoteknik ." Date: Wed, 28 May 2025 09:00:30 +0700 Subject: (andri) penambahan log note ketika biteship berhasil & penyesuaian field required pada SO --- indoteknik_custom/models/stock_picking.py | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'indoteknik_custom/models/stock_picking.py') diff --git a/indoteknik_custom/models/stock_picking.py b/indoteknik_custom/models/stock_picking.py index 5548db75..4522dac0 100644 --- a/indoteknik_custom/models/stock_picking.py +++ b/indoteknik_custom/models/stock_picking.py @@ -617,6 +617,14 @@ class StockPicking(models.Model): waybill_id = data.get("courier", {}).get("waybill_id", "") + self.message_post( + body=f"📦 Biteship berhasil dilakukan.
" + f"Kurir: {self.carrier_id.name}
" + f"Tracking ID: {self.biteship_tracking_id or '-'}
" + f"Resi: {waybill_id or '-'}", + message_type="comment" + ) + message = f"✅ Berhasil Order ke Biteship! Resi: {waybill_id}" if waybill_id else "⚠️ Order berhasil, tetapi tidak ada nomor resi." return { -- cgit v1.2.3 From 6e56ffc2c5b5ee22bc97d2518274eeb8a959e80e Mon Sep 17 00:00:00 2001 From: "Indoteknik ." Date: Wed, 28 May 2025 15:16:40 +0700 Subject: (andri) penyesuaian request biteship di stock picking --- indoteknik_custom/models/stock_picking.py | 73 ++++++++++++++++++++----------- 1 file changed, 47 insertions(+), 26 deletions(-) (limited to 'indoteknik_custom/models/stock_picking.py') 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.
" + body=f"Biteship berhasil dilakukan.
" f"Kurir: {self.carrier_id.name}
" f"Tracking ID: {self.biteship_tracking_id or '-'}
" 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): -- cgit v1.2.3 From c652ee3e1f652d23e37833f01e3fdd7aa8e52021 Mon Sep 17 00:00:00 2001 From: "Indoteknik ." Date: Sat, 31 May 2025 11:03:06 +0700 Subject: (andri) add tracking biteship pada BU OUT & fix delivery departure & arrival date --- indoteknik_custom/models/stock_picking.py | 55 ++++++++++++++++++++++++++++++- 1 file changed, 54 insertions(+), 1 deletion(-) (limited to 'indoteknik_custom/models/stock_picking.py') diff --git a/indoteknik_custom/models/stock_picking.py b/indoteknik_custom/models/stock_picking.py index 54da700b..4d38e5b3 100644 --- a/indoteknik_custom/models/stock_picking.py +++ b/indoteknik_custom/models/stock_picking.py @@ -1551,7 +1551,60 @@ class StockPicking(models.Model): except Exception as e : _logger.error(f"Error fetching Biteship order for picking {self.id}: {str(e)}") return { 'error': str(e) } - + + def action_sync_biteship_tracking(self): + for picking in self: + if not picking.biteship_id: + raise UserError("Tracking Biteship tidak tersedia.") + + histori = picking.get_manifest_biteship() + updated_fields = {} + seen_logs = set() + + manifests = sorted(histori.get("manifests", []), key=lambda m: m.get("datetime") or "") + + for manifest in manifests: + status = manifest.get("status", "").lower() + dt_str = manifest.get("datetime") + desc = manifest.get("description") + dt = False + + try: + local_dt_str = picking._convert_to_local_time(dt_str) + dt = fields.Datetime.from_string(local_dt_str) + except Exception as e: + _logger.warning(f"[Biteship Sync] Gagal parse datetime: {e}") + continue + + # Update tanggal ke field + if status == "picked" and dt and not picking.driver_departure_date: + updated_fields["driver_departure_date"] = dt + + if status == "delivered" and dt and not picking.driver_arrival_date: + updated_fields["driver_arrival_date"] = dt + + # Buat log unik + if dt and desc: + desc_clean = ' '.join(desc.strip().split()) + log_line = f"[TRACKING] {status} - {dt.strftime('%d %b %Y %H:%M')}: {desc_clean}" + if not picking._has_existing_log(log_line): + picking.message_post(body=log_line) + seen_logs.add(log_line) + + if updated_fields: + picking.write(updated_fields) + + def _has_existing_log(self, log_line): + self.ensure_one() + self.env.cr.execute(""" + SELECT 1 FROM mail_message + WHERE model = %s AND res_id = %s + AND subtype_id IS NOT NULL + AND body ILIKE %s + LIMIT 1 + """, (self._name, self.id, f"%{log_line}%")) + return self.env.cr.fetchone() is not None + def _convert_to_local_time(self, iso_date): try: dt_with_tz = waktu.fromisoformat(iso_date) -- cgit v1.2.3 From b6928c9bffc486b471d4c335c2550cbc1bf7d841 Mon Sep 17 00:00:00 2001 From: "Indoteknik ." Date: Sat, 31 May 2025 12:32:45 +0700 Subject: (andri) fix bug datetime departure&arrival --- indoteknik_custom/models/stock_picking.py | 34 ++++++++++++++++++------------- 1 file changed, 20 insertions(+), 14 deletions(-) (limited to 'indoteknik_custom/models/stock_picking.py') diff --git a/indoteknik_custom/models/stock_picking.py b/indoteknik_custom/models/stock_picking.py index 4d38e5b3..4517a941 100644 --- a/indoteknik_custom/models/stock_picking.py +++ b/indoteknik_custom/models/stock_picking.py @@ -1570,23 +1570,23 @@ class StockPicking(models.Model): dt = False try: - local_dt_str = picking._convert_to_local_time(dt_str) - dt = fields.Datetime.from_string(local_dt_str) + dt = picking._convert_to_local_time(dt_str) except Exception as e: _logger.warning(f"[Biteship Sync] Gagal parse datetime: {e}") continue - # Update tanggal ke field + # Update tanggal ke field (pastikan naive datetime UTC) if status == "picked" and dt and not picking.driver_departure_date: - updated_fields["driver_departure_date"] = dt + updated_fields["driver_departure_date"] = fields.Datetime.to_string(dt) if status == "delivered" and dt and not picking.driver_arrival_date: - updated_fields["driver_arrival_date"] = dt + updated_fields["driver_arrival_date"] = fields.Datetime.to_string(dt) - # Buat log unik + # Buat log unik dengan waktu lokal Asia/Jakarta if dt and desc: + dt_local = pytz.utc.localize(dt).astimezone(pytz.timezone("Asia/Jakarta")) desc_clean = ' '.join(desc.strip().split()) - log_line = f"[TRACKING] {status} - {dt.strftime('%d %b %Y %H:%M')}: {desc_clean}" + log_line = f"[TRACKING] {status} - {dt_local.strftime('%d %b %Y %H:%M')}: {desc_clean}" if not picking._has_existing_log(log_line): picking.message_post(body=log_line) seen_logs.add(log_line) @@ -1607,15 +1607,21 @@ class StockPicking(models.Model): def _convert_to_local_time(self, iso_date): try: - dt_with_tz = waktu.fromisoformat(iso_date) - utc_dt = dt_with_tz.astimezone(pytz.utc) - + from dateutil import parser + import pytz + if isinstance(iso_date, str): + waktu = parser.parse(iso_date) + else: + waktu = iso_date + if waktu.tzinfo is None: + waktu = waktu.replace(tzinfo=pytz.utc) local_tz = pytz.timezone("Asia/Jakarta") - local_dt = utc_dt.astimezone(local_tz) - - return local_dt.strftime("%Y-%m-%d %H:%M:%S") + local_dt = waktu.astimezone(local_tz) + utc_dt = local_dt.astimezone(pytz.utc).replace(tzinfo=None) + return utc_dt except Exception as e: - return str(e) + _logger.warning(f"[Biteship] Gagal konversi waktu lokal: {e}") + return False def _map_status_biteship(self, status): status_mapping = { -- cgit v1.2.3 From 43d180117e90db9115f07ab4b5b2880c32594bea Mon Sep 17 00:00:00 2001 From: "Indoteknik ." Date: Mon, 2 Jun 2025 12:09:27 +0700 Subject: (andri) fix date tracking --- indoteknik_custom/models/stock_picking.py | 34 +++++++++++++++++++++++-------- 1 file changed, 26 insertions(+), 8 deletions(-) (limited to 'indoteknik_custom/models/stock_picking.py') diff --git a/indoteknik_custom/models/stock_picking.py b/indoteknik_custom/models/stock_picking.py index 4517a941..a2935a07 100644 --- a/indoteknik_custom/models/stock_picking.py +++ b/indoteknik_custom/models/stock_picking.py @@ -1570,7 +1570,8 @@ class StockPicking(models.Model): dt = False try: - dt = picking._convert_to_local_time(dt_str) + dt = picking._convert_to_utc_datetime(dt_str) + _logger.info(f"[Biteship Sync] Berhasil parse datetime: {dt_str} -> {dt}") except Exception as e: _logger.warning(f"[Biteship Sync] Gagal parse datetime: {e}") continue @@ -1584,7 +1585,12 @@ class StockPicking(models.Model): # Buat log unik dengan waktu lokal Asia/Jakarta if dt and desc: - dt_local = pytz.utc.localize(dt).astimezone(pytz.timezone("Asia/Jakarta")) + try: + dt_local = parser.parse(dt_str).replace(tzinfo=None) + except Exception as e: + _logger.warning(f"[Biteship Sync] Gagal parse dt_str untuk log: {e}") + dt_local = dt # fallback + desc_clean = ' '.join(desc.strip().split()) log_line = f"[TRACKING] {status} - {dt_local.strftime('%d %b %Y %H:%M')}: {desc_clean}" if not picking._has_existing_log(log_line): @@ -1605,10 +1611,24 @@ class StockPicking(models.Model): """, (self._name, self.id, f"%{log_line}%")) return self.env.cr.fetchone() is not None + # Untuk internal Odoo (mengembalikan naive UTC datetime untuk disimpan ke DB) + def _convert_to_utc_datetime(self, iso_date): + try: + if isinstance(iso_date, str): + waktu = parser.parse(iso_date) + else: + waktu = iso_date + if waktu.tzinfo is None: + waktu = waktu.replace(tzinfo=pytz.utc) + utc_dt = waktu.astimezone(pytz.utc).replace(tzinfo=None) + return utc_dt + except Exception as e: + _logger.warning(f"[Biteship] Gagal konversi waktu UTC: {e}") + return False + + # Untuk tampilan di API atau kebutuhan web (mengembalikan string waktu lokal) def _convert_to_local_time(self, iso_date): try: - from dateutil import parser - import pytz if isinstance(iso_date, str): waktu = parser.parse(iso_date) else: @@ -1617,11 +1637,9 @@ class StockPicking(models.Model): waktu = waktu.replace(tzinfo=pytz.utc) local_tz = pytz.timezone("Asia/Jakarta") local_dt = waktu.astimezone(local_tz) - utc_dt = local_dt.astimezone(pytz.utc).replace(tzinfo=None) - return utc_dt + return local_dt.strftime("%Y-%m-%d %H:%M:%S") except Exception as e: - _logger.warning(f"[Biteship] Gagal konversi waktu lokal: {e}") - return False + return str(e) def _map_status_biteship(self, status): status_mapping = { -- cgit v1.2.3 From d6f3060b46582ddd78f596ce3527871cae1b2b46 Mon Sep 17 00:00:00 2001 From: "Indoteknik ." Date: Tue, 3 Jun 2025 14:08:30 +0700 Subject: (andri) ganti referensi dari no SO ke no BU OUT --- indoteknik_custom/models/stock_picking.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'indoteknik_custom/models/stock_picking.py') diff --git a/indoteknik_custom/models/stock_picking.py b/indoteknik_custom/models/stock_picking.py index a2935a07..39872ecb 100644 --- a/indoteknik_custom/models/stock_picking.py +++ b/indoteknik_custom/models/stock_picking.py @@ -568,13 +568,13 @@ class StockPicking(models.Model): _logger.info(f"Items data standard: {items_data_standard}") _logger.info(f"Items data instant: {items_data_instant}") - # Bangun payload dasar + payload = { "origin_coordinate": { "latitude": -6.3031123, "longitude": 106.7794934999 }, - "reference_id": self.sale_id.name, + "reference_id": self.name, # PERUBAHAN: Gunakan nomor BU/OUT "shipper_contact_name": self.carrier_id.pic_name or '', "shipper_contact_phone": self.carrier_id.pic_phone or '', "shipper_organization": self.carrier_id.name, @@ -587,6 +587,7 @@ class StockPicking(models.Model): "destination_address": self.real_shipping_id.street, "destination_postal_code": self.real_shipping_id.zip, "origin_note": "BELAKANG INDOMARET", + "destination_note": f"SO: {self.sale_id.name}", # PERUBAHAN: Tambahkan SO ke note "courier_type": self.sale_id.delivery_service_type or "reg", "courier_company": self.carrier_id.name.lower(), "delivery_type": "now", @@ -640,7 +641,9 @@ class StockPicking(models.Model): body=f"Biteship berhasil dilakukan.
" f"Kurir: {self.carrier_id.name}
" f"Tracking ID: {self.biteship_tracking_id or '-'}
" - f"Resi: {waybill_id or '-'}", + f"Resi: {waybill_id or '-'}
" + f"Reference: {self.name}
" + f"SO: {self.sale_id.name}", message_type="comment" ) -- cgit v1.2.3 From b519e0fdac46a64ffef87d27ba824038147d831b Mon Sep 17 00:00:00 2001 From: "Indoteknik ." Date: Tue, 3 Jun 2025 15:36:08 +0700 Subject: (andri) memastikan order sesuai dengan informasi barang yang ingin dikirim --- indoteknik_custom/models/stock_picking.py | 98 ++++++++++++------------------- 1 file changed, 39 insertions(+), 59 deletions(-) (limited to 'indoteknik_custom/models/stock_picking.py') diff --git a/indoteknik_custom/models/stock_picking.py b/indoteknik_custom/models/stock_picking.py index 39872ecb..cdff6e32 100644 --- a/indoteknik_custom/models/stock_picking.py +++ b/indoteknik_custom/models/stock_picking.py @@ -526,7 +526,6 @@ 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}") - # Fungsi bantu: menentukan apakah kurir perlu koordinat def is_courier_need_coordinates(service_code): return service_code in [ "instant", "same_day", "instant_car", @@ -534,47 +533,42 @@ class StockPicking(models.Model): "cdd_bak", "cdd_box", "engkel_box", "engkel_bak" ] - # Ambil order line - products = self.env['sale.order.line'].search([('order_id', '=', self.sale_id.id)]) - - # 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*1000 - } for line in lines] - - items_data_standard = build_items_data(products) + # ✅ Ambil item dari move_line_ids_with_package (qty_done > 0) + items = [] + for ml in self.move_line_ids_without_package: + if ml.qty_done <= 0: + continue - # Bangun data items untuk pengiriman instant - items_data_instant = [] - for move_line in self.move_line_ids_without_package: - order_line = self.env['sale.order.line'].search([ + product = ml.product_id + weight = product.weight or 0.1 # default minimal + line = ml.sale_line_id or self.env['sale.order.line'].search([ ('order_id', '=', self.sale_id.id), - ('product_id', '=', move_line.product_id.id) + ('product_id', '=', product.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*1000 - }) + value = line.price_unit if line else 0 + description = line.name if line else product.name + + items.append({ + "name": product.name, + "description": description, + "value": value, + "quantity": ml.qty_done, + "weight": int(weight * 1000), + }) - _logger.info(f"Items data standard: {items_data_standard}") - _logger.info(f"Items data instant: {items_data_instant}") + if not items: + raise UserError("Pengiriman tidak dapat dilakukan karena tidak ada barang yang divalidasi (qty_done = 0).") + + shipping_partner = self.real_shipping_id + courier_service_code = self.sale_id.delivery_service_type or "reg" payload = { "origin_coordinate": { "latitude": -6.3031123, "longitude": 106.7794934999 }, - "reference_id": self.name, # PERUBAHAN: Gunakan nomor BU/OUT + "reference_id": self.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, @@ -582,38 +576,26 @@ class StockPicking(models.Model): "origin_contact_phone": "081717181922", "origin_address": "Jl. Bandengan Utara Komp A & BRT. Penjaringan, Kec. Penjaringan, Jakarta (BELAKANG INDOMARET) KOTA JAKARTA UTARA PENJARINGAN", "origin_postal_code": 14440, - "destination_contact_name": self.real_shipping_id.name, - "destination_contact_phone": self.real_shipping_id.phone or self.real_shipping_id.mobile, - "destination_address": self.real_shipping_id.street, - "destination_postal_code": self.real_shipping_id.zip, + "destination_contact_name": shipping_partner.name, + "destination_contact_phone": shipping_partner.phone or shipping_partner.mobile, + "destination_address": shipping_partner.street, + "destination_postal_code": shipping_partner.zip, "origin_note": "BELAKANG INDOMARET", - "destination_note": f"SO: {self.sale_id.name}", # PERUBAHAN: Tambahkan SO ke note - "courier_type": self.sale_id.delivery_service_type or "reg", + "destination_note": f"SO: {self.sale_id.name}", + "courier_type": courier_service_code, "courier_company": self.carrier_id.name.lower(), "delivery_type": "now", - "items": items_data_standard + "items": items } - _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: + if is_courier_need_coordinates(courier_service_code): + if not shipping_partner.latitude or not shipping_partner.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.") - - payload.update({ - "destination_coordinate": { - "latitude": self.real_shipping_id.latitude, - "longitude": self.real_shipping_id.longtitude, - }, - "items": items_data_instant - }) + payload["destination_coordinate"] = { + "latitude": shipping_partner.latitude, + "longitude": shipping_partner.longtitude, + } _logger.info(f"Payload untuk Biteship: {payload}") @@ -633,7 +615,7 @@ class StockPicking(models.Model): self.biteship_id = data.get("id", "") 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", "") + self.delivery_tracking_no = self.biteship_waybill_id waybill_id = self.biteship_waybill_id @@ -656,13 +638,11 @@ class StockPicking(models.Model): '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): -- cgit v1.2.3 From 8a9c08a21fd7d2ac63ef849d9417b11563092f0d Mon Sep 17 00:00:00 2001 From: "Indoteknik ." Date: Tue, 3 Jun 2025 21:10:12 +0700 Subject: (andri) perbaikan biteship pada stock picking --- indoteknik_custom/models/stock_picking.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'indoteknik_custom/models/stock_picking.py') diff --git a/indoteknik_custom/models/stock_picking.py b/indoteknik_custom/models/stock_picking.py index cdff6e32..7e001299 100644 --- a/indoteknik_custom/models/stock_picking.py +++ b/indoteknik_custom/models/stock_picking.py @@ -541,9 +541,9 @@ class StockPicking(models.Model): product = ml.product_id weight = product.weight or 0.1 # default minimal - line = ml.sale_line_id or self.env['sale.order.line'].search([ + line = ml.move_id.sale_line_id or self.env['sale.order.line'].search([ ('order_id', '=', self.sale_id.id), - ('product_id', '=', product.id) + ('product_id', '=', ml.product_id.id) ], limit=1) value = line.price_unit if line else 0 -- cgit v1.2.3 From 288a7f333c1d37574dba76f3fb3f7216da259cae Mon Sep 17 00:00:00 2001 From: "Indoteknik ." Date: Sat, 7 Jun 2025 09:41:27 +0700 Subject: (andri) add field shipping option pada stock picking sebagai tambahan info --- indoteknik_custom/models/stock_picking.py | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'indoteknik_custom/models/stock_picking.py') diff --git a/indoteknik_custom/models/stock_picking.py b/indoteknik_custom/models/stock_picking.py index 7e001299..d6413b87 100644 --- a/indoteknik_custom/models/stock_picking.py +++ b/indoteknik_custom/models/stock_picking.py @@ -244,6 +244,11 @@ class StockPicking(models.Model): biteship_waybill_id = fields.Char(string="Biteship Waybill ID") final_seq = fields.Float(string='Remaining Time') shipping_method_so_id = fields.Many2one('delivery.carrier', string='Shipping Method SO', related='sale_id.carrier_id') + shipping_option_so_id = fields.Many2one('shipping.option', string='Shipping Option SO', related='sale_id.shipping_option_id') + select_shipping_option_so = fields.Selection([ + ('biteship', 'Biteship'), + ('custom', 'Custom'), + ], string='Shipping Type SO', related='sale_id.select_shipping_option') state_packing = fields.Selection([('not_packing', 'Belum Packing'), ('packing_done', 'Sudah Packing')], string='Packing Status') approval_invoice_date_id = fields.Many2one('approval.invoice.date', string='Approval Invoice Date') last_update_date_doc_kirim = fields.Datetime(string='Last Update Tanggal Kirim') -- cgit v1.2.3 From de747091235c844d33bcf62b4d98af0d03251826 Mon Sep 17 00:00:00 2001 From: "Indoteknik ." Date: Mon, 9 Jun 2025 11:37:19 +0700 Subject: (andri) fix note order biteship --- indoteknik_custom/models/stock_picking.py | 1 + 1 file changed, 1 insertion(+) (limited to 'indoteknik_custom/models/stock_picking.py') diff --git a/indoteknik_custom/models/stock_picking.py b/indoteknik_custom/models/stock_picking.py index d6413b87..d04b3d27 100644 --- a/indoteknik_custom/models/stock_picking.py +++ b/indoteknik_custom/models/stock_picking.py @@ -587,6 +587,7 @@ class StockPicking(models.Model): "destination_postal_code": shipping_partner.zip, "origin_note": "BELAKANG INDOMARET", "destination_note": f"SO: {self.sale_id.name}", + "order_note": f"SO: {self.sale_id.name}", "courier_type": courier_service_code, "courier_company": self.carrier_id.name.lower(), "delivery_type": "now", -- cgit v1.2.3 From 1a63fac5f7f4dbb2990e5b1eeb9d7f381f39e908 Mon Sep 17 00:00:00 2001 From: Miqdad Date: Mon, 9 Jun 2025 20:35:35 +0700 Subject: add products in manifest --- indoteknik_custom/models/stock_picking.py | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) (limited to 'indoteknik_custom/models/stock_picking.py') diff --git a/indoteknik_custom/models/stock_picking.py b/indoteknik_custom/models/stock_picking.py index 71eca020..ae3c8f1d 100644 --- a/indoteknik_custom/models/stock_picking.py +++ b/indoteknik_custom/models/stock_picking.py @@ -1646,6 +1646,14 @@ class StockPicking(models.Model): sale_order_delay = self.env['sale.order.delay'].search([('so_number', '=', order.name)], limit=1) + product_shipped = [] + for move_line in self.move_line_ids_without_package: + if move_line.qty_done > 0: + product_shipped.append({ + 'name': move_line.product_id.name, + 'qty': move_line.qty_done + }) + response = { 'delivery_order': { 'name': self.name, @@ -1662,7 +1670,8 @@ class StockPicking(models.Model): 'eta': self.generate_eta_delivery(), 'is_biteship': True if self.biteship_id else False, 'manifests': self.get_manifests(), - 'is_delay': True if sale_order_delay and sale_order_delay.status == 'delayed' else False + 'is_delay': True if sale_order_delay and sale_order_delay.status == 'delayed' else False, + 'products': product_shipped } if self.biteship_id: -- cgit v1.2.3 From 8ac5d556a6686c6b81d5e9178bff5d308e8f176f Mon Sep 17 00:00:00 2001 From: "Indoteknik ." Date: Thu, 12 Jun 2025 15:11:06 +0700 Subject: (andri) add validasi tidak bisa kirim biteship (stock picking) jika shipping option SO adalah custom --- indoteknik_custom/models/stock_picking.py | 3 +++ 1 file changed, 3 insertions(+) (limited to 'indoteknik_custom/models/stock_picking.py') diff --git a/indoteknik_custom/models/stock_picking.py b/indoteknik_custom/models/stock_picking.py index ae3c8f1d..8b03e18d 100644 --- a/indoteknik_custom/models/stock_picking.py +++ b/indoteknik_custom/models/stock_picking.py @@ -690,6 +690,9 @@ class StockPicking(models.Model): def action_send_to_biteship(self): if self.biteship_tracking_id: raise UserError(f"Order ini sudah dikirim ke Biteship. Dengan Tracking Id: {self.biteship_tracking_id}") + + if self.sale_id.select_shipping_option == 'custom': + raise UserError("Shipping Option pada Sales Order ini adalah *Custom*. Tidak dapat dikirim melalui Biteship.") def is_courier_need_coordinates(service_code): return service_code in [ -- cgit v1.2.3 From 819f7c2f0dfe0eaf857c44e80062dcc7e94c9828 Mon Sep 17 00:00:00 2001 From: "Indoteknik ." Date: Sat, 14 Jun 2025 13:06:43 +0700 Subject: (andri) memindahkan key biteship (test&live) ke system parameter --- indoteknik_custom/models/stock_picking.py | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) (limited to 'indoteknik_custom/models/stock_picking.py') diff --git a/indoteknik_custom/models/stock_picking.py b/indoteknik_custom/models/stock_picking.py index 8b03e18d..89e7fecc 100644 --- a/indoteknik_custom/models/stock_picking.py +++ b/indoteknik_custom/models/stock_picking.py @@ -19,11 +19,6 @@ import re _logger = logging.getLogger(__name__) _biteship_url = "https://api.biteship.com/v1" -_biteship_api_key = "biteship_test.eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYW1lIjoiSW5kb3Rla25payIsInVzZXJJZCI6IjY3MTViYTJkYzVkMjdkMDAxMjRjODk2MiIsImlhdCI6MTcyOTQ5ODAwMX0.L6C73couP4-cgVEfhKI2g7eMCMo3YOFSRZhS-KSuHNA" - - -# _biteship_api_key = "biteship_live.eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYW1lIjoiaW5kb3Rla25payIsInVzZXJJZCI6IjY3MTViYTJkYzVkMjdkMDAxMjRjODk2MiIsImlhdCI6MTc0MTE1NTU4M30.pbFCai9QJv8iWhgdosf8ScVmEeP3e5blrn33CHe7Hgo" - class StockPicking(models.Model): _inherit = 'stock.picking' @@ -170,6 +165,10 @@ class StockPicking(models.Model): area_name = fields.Char(string="Area", compute="_compute_area_name") + def _get_biteship_api_key(self): + return self.env['ir.config_parameter'].sudo().get_param('biteship.api_key_test') + # return self.env['ir.config_parameter'].sudo().get_param('biteship.api_key_live') + @api.depends('real_shipping_id.kecamatan_id', 'real_shipping_id.kota_id') def _compute_area_name(self): for record in self: @@ -769,7 +768,7 @@ class StockPicking(models.Model): _logger.info(f"Payload untuk Biteship: {payload}") # Kirim ke Biteship - api_key = _biteship_api_key + api_key = self._get_biteship_api_key() headers = { "Authorization": f"Bearer {api_key}", "Content-Type": "application/json" @@ -1712,7 +1711,7 @@ class StockPicking(models.Model): return response def get_manifest_biteship(self): - api_key = _biteship_api_key + api_key = self._get_biteship_api_key() headers = { "Authorization": f"Bearer {api_key}", "Content-Type": "application/json" -- cgit v1.2.3 From 8718c383e39440f83d6579ef536478053e623bc3 Mon Sep 17 00:00:00 2001 From: "Indoteknik ." Date: Sat, 14 Jun 2025 13:14:24 +0700 Subject: (andri) live biteship --- indoteknik_custom/models/stock_picking.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'indoteknik_custom/models/stock_picking.py') diff --git a/indoteknik_custom/models/stock_picking.py b/indoteknik_custom/models/stock_picking.py index 89e7fecc..7775e991 100644 --- a/indoteknik_custom/models/stock_picking.py +++ b/indoteknik_custom/models/stock_picking.py @@ -166,8 +166,8 @@ class StockPicking(models.Model): area_name = fields.Char(string="Area", compute="_compute_area_name") def _get_biteship_api_key(self): - return self.env['ir.config_parameter'].sudo().get_param('biteship.api_key_test') - # return self.env['ir.config_parameter'].sudo().get_param('biteship.api_key_live') + # return self.env['ir.config_parameter'].sudo().get_param('biteship.api_key_test') + return self.env['ir.config_parameter'].sudo().get_param('biteship.api_key_live') @api.depends('real_shipping_id.kecamatan_id', 'real_shipping_id.kota_id') def _compute_area_name(self): -- cgit v1.2.3 From dba82e88291ac63473b8f45dd7a4da5b4d147973 Mon Sep 17 00:00:00 2001 From: Azka Nathan Date: Mon, 16 Jun 2025 14:00:14 +0700 Subject: push --- indoteknik_custom/models/stock_picking.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'indoteknik_custom/models/stock_picking.py') diff --git a/indoteknik_custom/models/stock_picking.py b/indoteknik_custom/models/stock_picking.py index 6eac857c..92317334 100644 --- a/indoteknik_custom/models/stock_picking.py +++ b/indoteknik_custom/models/stock_picking.py @@ -1362,7 +1362,7 @@ class StockPicking(models.Model): picking_date = fields.Date.to_date(picking.date_doc_kirim) invoice_date = fields.Date.to_date(invoice.invoice_date) - if picking_date != invoice_date and picking.update_date_doc_kirim_add: + if picking_date != invoice_date and picking.update_date_doc_kirim_add and not picking.so_lama: raise UserError("Tanggal Kirim (%s) tidak sesuai dengan Tanggal Invoice (%s)!" % ( picking_date.strftime('%d-%m-%Y'), invoice_date.strftime('%d-%m-%Y') -- cgit v1.2.3 From 3c8ff8cb6a24dd1ddec7d34313722d7dee6f23a3 Mon Sep 17 00:00:00 2001 From: "Indoteknik ." Date: Mon, 16 Jun 2025 16:15:57 +0700 Subject: (andri) taruh key hardcode --- indoteknik_custom/models/stock_picking.py | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) (limited to 'indoteknik_custom/models/stock_picking.py') diff --git a/indoteknik_custom/models/stock_picking.py b/indoteknik_custom/models/stock_picking.py index 6eac857c..f552ff3f 100644 --- a/indoteknik_custom/models/stock_picking.py +++ b/indoteknik_custom/models/stock_picking.py @@ -19,6 +19,9 @@ import re _logger = logging.getLogger(__name__) _biteship_url = "https://api.biteship.com/v1" +biteship_api_key = "biteship_live.eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYW1lIjoiaW5kb3Rla25payIsInVzZXJJZCI6IjY3MTViYTJkYzVkMjdkMDAxMjRjODk2MiIsImlhdCI6MTc0MTE1NTU4M30.pbFCai9QJv8iWhgdosf8ScVmEeP3e5blrn33CHe7Hgo" +# biteship_api_key = "biteship_test.eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYW1lIjoiSW5kb3Rla25payIsInVzZXJJZCI6IjY3MTViYTJkYzVkMjdkMDAxMjRjODk2MiIsImlhdCI6MTcyOTQ5ODAwMX0.L6C73couP4-cgVEfhKI2g7eMCMo3YOFSRZhS-KSuHNA" + class StockPicking(models.Model): _inherit = 'stock.picking' @@ -165,9 +168,9 @@ class StockPicking(models.Model): area_name = fields.Char(string="Area", compute="_compute_area_name") - def _get_biteship_api_key(self): - # return self.env['ir.config_parameter'].sudo().get_param('biteship.api_key_test') - return self.env['ir.config_parameter'].sudo().get_param('biteship.api_key_live') + # def _get_biteship_api_key(self): + # # return self.env['ir.config_parameter'].sudo().get_param('biteship.api_key_test') + # return self.env['ir.config_parameter'].sudo().get_param('biteship.api_key_live') @api.depends('real_shipping_id.kecamatan_id', 'real_shipping_id.kota_id') def _compute_area_name(self): @@ -762,7 +765,7 @@ class StockPicking(models.Model): _logger.info(f"Payload untuk Biteship: {payload}") # Kirim ke Biteship - api_key = self._get_biteship_api_key() + api_key = biteship_api_key headers = { "Authorization": f"Bearer {api_key}", "Content-Type": "application/json" @@ -1705,7 +1708,7 @@ class StockPicking(models.Model): return response def get_manifest_biteship(self): - api_key = self._get_biteship_api_key() + api_key = biteship_api_key headers = { "Authorization": f"Bearer {api_key}", "Content-Type": "application/json" -- cgit v1.2.3