From 2b1783368e7be632e18be524b5288713125e7902 Mon Sep 17 00:00:00 2001 From: trisusilo48 Date: Thu, 13 Mar 2025 11:25:22 +0700 Subject: uat bitehsip --- indoteknik_api/controllers/api_v1/product.py | 5 +++- indoteknik_custom/models/sale_order.py | 34 ++++++++++++---------------- indoteknik_custom/models/stock_picking.py | 17 ++++++++++---- 3 files changed, 32 insertions(+), 24 deletions(-) diff --git a/indoteknik_api/controllers/api_v1/product.py b/indoteknik_api/controllers/api_v1/product.py index 557215ea..ef2d8bf2 100644 --- a/indoteknik_api/controllers/api_v1/product.py +++ b/indoteknik_api/controllers/api_v1/product.py @@ -34,9 +34,12 @@ class Product(controller.Controller): categories.reverse() return self.response(categories, headers=[('Cache-Control', 'max-age=3600, public')]) - @http.route(prefix + 'product/variants/sla', auth='public', methods=['GET', 'OPTIONS']) + @http.route(prefix + 'product/variants/sla', auth='public', methods=['POST', 'OPTIONS']) @controller.Controller.must_authorized() def get_product_template_sla_by_id(self, **kwargs): + params = kwargs + + body_params = kwargs.get('ids') if not body_params: diff --git a/indoteknik_custom/models/sale_order.py b/indoteknik_custom/models/sale_order.py index 852e3cf0..b22ee2ee 100755 --- a/indoteknik_custom/models/sale_order.py +++ b/indoteknik_custom/models/sale_order.py @@ -498,7 +498,6 @@ class SaleOrder(models.Model): if all_fast_products: return {'slatime': 1, 'include_instant': include_instant} - # Cari semua vendor pemenang untuk produk yang diberikan vendors = self.env['purchase.pricelist'].search([ ('product_id', 'in', product_ids), @@ -532,18 +531,18 @@ class SaleOrder(models.Model): max_slatime = 1 # Default SLA jika tidak ada slatime = self.calculate_sla_by_vendor(rec.order_line) max_slatime = max(max_slatime, slatime['slatime']) + + + current_date = datetime.now().date() if rec.date_order: - sum_days = max_slatime + self.get_days_until_next_business_day(rec.date_order) - 1 - if not rec.estimated_arrival_days: - rec.estimated_arrival_days = sum_days - - eta_date = rec.date_order + timedelta(days=sum_days) + sum_days = max_slatime + self.get_days_until_next_business_day(current_date) - 1 + rec.estimated_arrival_days = sum_days + + eta_date = current_date + timedelta(days=sum_days) rec.estimated_ready_ship_date = eta_date rec.commitment_date = eta_date - # Jika expected_ready_to_ship kosong, set nilai default - if not rec.expected_ready_to_ship: - rec.expected_ready_to_ship = eta_date + rec.expected_ready_to_ship = eta_date @@ -765,14 +764,10 @@ class SaleOrder(models.Model): def write(self, vals): - res = super(SaleOrder, self).write(vals) - # self._compute_etrts_date() if 'carrier_id' in vals: for picking in self.picking_ids: if picking.state == 'assigned': picking.carrier_id = self.carrier_id - - return res def calculate_so_status(self): so_state = ['sale'] @@ -1229,7 +1224,7 @@ class SaleOrder(models.Model): order._set_sppkp_npwp_contact() order.calculate_line_no() order.send_notif_to_salesperson() - order._compute_etrts_date() + # order._compute_etrts_date() # order.order_line.get_reserved_from() res = super(SaleOrder, self).action_confirm() @@ -1629,15 +1624,15 @@ class SaleOrder(models.Model): # order._update_partner_details() return order - def write(self, vals): + # def write(self, vals): # Call the super method to handle the write operation - res = super(SaleOrder, self).write(vals) + # res = super(SaleOrder, self).write(vals) # self._compute_etrts_date() # Check if the update is coming from a save operation # if any(field in vals for field in ['sppkp', 'npwp', 'email', 'customer_type']): # self._update_partner_details() - return res + # return res def _update_partner_details(self): for order in self: @@ -1666,7 +1661,8 @@ class SaleOrder(models.Model): if command[0] == 0: # A new line is being added raise UserError( "SO tidak dapat ditambahkan produk baru karena SO sudah menjadi sale order.") + res = super(SaleOrder, self).write(vals) - if 'order_line' in vals: - self._compute_etrts_date() + if any(field in vals for field in ["order_line", "client_order_ref"]): + self._compute_etrts_date() return res \ No newline at end of file diff --git a/indoteknik_custom/models/stock_picking.py b/indoteknik_custom/models/stock_picking.py index ab8109c7..edc9cc78 100644 --- a/indoteknik_custom/models/stock_picking.py +++ b/indoteknik_custom/models/stock_picking.py @@ -13,11 +13,11 @@ import requests import time import logging import re -from deep_translator import GoogleTranslator _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" +# _biteship_api_key = "biteship_live.eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYW1lIjoiaW5kb3Rla25payIsInVzZXJJZCI6IjY3MTViYTJkYzVkMjdkMDAxMjRjODk2MiIsImlhdCI6MTc0MTE1NTU4M30.pbFCai9QJv8iWhgdosf8ScVmEeP3e5blrn33CHe7Hgo" @@ -492,8 +492,18 @@ 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", "") + + message = f"✅ Berhasil Order ke Biteship! Resi: {waybill_id}" if waybill_id else "⚠️ Order berhasil, tetapi tidak ada nomor resi." - return data + return { + 'effect': { + 'fadeout': 'slow', # Efek menghilang perlahan + 'message': message, # Pesan sukses + 'type': 'rainbow_man', # Efek animasi lucu Odoo + } + } else: error_data = response.json() error_message = error_data.get("error", "Unknown error") @@ -1203,7 +1213,6 @@ class StockPicking(models.Model): manifests.append({ "status": re.sub(r'[^a-zA-Z0-9\s]', ' ', entry["status"]).lower().capitalize(), "datetime": self._convert_to_local_time(entry["updated_at"]), - # "description": GoogleTranslator(source='auto', target='id').translate(entry["note"]), "description": description[entry["status"]], }) -- cgit v1.2.3 From e4d86ee7cb2fac5c09876b1aeefda04f27ebedd0 Mon Sep 17 00:00:00 2001 From: trisusilo48 Date: Mon, 17 Mar 2025 09:03:51 +0700 Subject: biteship handle sla SO --- indoteknik_api/controllers/api_v1/product.py | 97 +++++++++++++------------ indoteknik_api/controllers/api_v1/sale_order.py | 2 + indoteknik_custom/models/sale_order.py | 36 ++++----- 3 files changed, 71 insertions(+), 64 deletions(-) diff --git a/indoteknik_api/controllers/api_v1/product.py b/indoteknik_api/controllers/api_v1/product.py index ef2d8bf2..a88c3368 100644 --- a/indoteknik_api/controllers/api_v1/product.py +++ b/indoteknik_api/controllers/api_v1/product.py @@ -34,63 +34,66 @@ class Product(controller.Controller): categories.reverse() return self.response(categories, headers=[('Cache-Control', 'max-age=3600, public')]) - @http.route(prefix + 'product/variants/sla', auth='public', methods=['POST', 'OPTIONS']) + @http.route(prefix + 'product/variants/sla', auth='public', methods=['POST', 'OPTIONS'] , csrf=False) @controller.Controller.must_authorized() def get_product_template_sla_by_id(self, **kwargs): - params = kwargs + raw_data = kwargs.get('products', '[]') + product_data = json.loads(raw_data) - body_params = kwargs.get('ids') + product_ids = [int(item["id"]) for item in product_data] + products = request.env['purchase.pricelist'].search([ + ('product_id', 'in', product_ids), + ('is_winner', '=', True) + ]) - if not body_params: - return self.response('Failed', code=400, description='id is required') - - ids = [int(id.strip()) for id in body_params.split(',') if id.strip().isdigit()] - - sla_duration = 0 - sla_unit = 'Hari' + start_date = datetime.today().date() + additional_days = request.env['sale.order'].get_days_until_next_business_day(start_date) include_instant = True - products = request.env['product.product'].search([('id', 'in', ids)]) - if len(products) < 1: - return self.response( - 'Failed', - code=400, - description='Produk Tidak Di Temukan.' - ) - product_slas = request.env['product.sla'].search([('product_variant_id', 'in', ids)]) - if len(product_slas) < 1: - return self.response( - 'Failed', - code=400, - description='SLA Tidak Di Temukan.' - ) + if(len(products) != len(product_ids)): + products_data_params = {product["id"] : product for product in product_data } - # Mapping SLA untuk mempermudah lookup - sla_map = {sla.product_variant_id.id: sla for sla in product_slas} - - for product in products: - product_sla = sla_map.get(product.id) - if product_sla: - sla_duration = max(sla_duration, int(product_sla.sla)) - sla_unit = product_sla.sla_vendor_id.unit - if product.qty_free_bandengan < 1 : - if product_sla.sla_vendor_id.unit != 'jam': - include_instant = False - break - - start_date = datetime.today().date() - additional_days = request.env['sale.order'].get_days_until_next_business_day(start_date) + all_fast_products = all( + product.product_id.qty_free_bandengan >= products_data_params.get(product.product_id.id, {}).get("quantity", 0) + for product in products + ) - # Jika semua loop selesai tanpa include_instant menjadi False + if all_fast_products: + return self.response({ + 'include_instant': include_instant, + 'sla_duration': 1, + 'sla_additional_days': additional_days, + 'sla_total' : int(1) + int(additional_days), + 'sla_unit': 'Hari' + }) + + max_slatime = 1 + + for vendor in products: + vendor_sla = request.env['vendor.sla'].search([('id_vendor', '=', vendor.vendor_id.id)], limit=1) + slatime = 15 + if vendor_sla: + if vendor_sla.unit == 'hari': + vendor_duration = vendor_sla.duration * 24 * 60 + include_instant = False + else : + vendor_duration = vendor_sla.duration * 60 + include_instant = True + + estimation_sla = (1 * 24 * 60) + vendor_duration + estimation_sla_days = estimation_sla / (24 * 60) + slatime = math.ceil(estimation_sla_days) + + max_slatime = max(max_slatime, slatime) + return self.response({ - 'include_instant': include_instant, - 'sla_duration': sla_duration, - 'sla_additional_days': additional_days, - 'sla_total' : int(sla_duration) + int(additional_days), - 'sla_unit': 'Hari' if additional_days > 0 else sla_unit - } - ) + 'include_instant': include_instant, + 'sla_duration': max_slatime, + 'sla_additional_days': additional_days, + 'sla_total' : int(max_slatime) + int(additional_days), + 'sla_unit': 'Hari' + }) @http.route(prefix + 'product_variant//stock', auth='public', methods=['GET', 'OPTIONS']) @controller.Controller.must_authorized() diff --git a/indoteknik_api/controllers/api_v1/sale_order.py b/indoteknik_api/controllers/api_v1/sale_order.py index 6815bf6c..98b13cad 100644 --- a/indoteknik_api/controllers/api_v1/sale_order.py +++ b/indoteknik_api/controllers/api_v1/sale_order.py @@ -466,6 +466,8 @@ class SaleOrder(controller.Controller): 'program_line_id': cart['id'], 'quantity': cart['quantity'] }) + + sale_order._compute_etrts_date() request.env['sale.order.promotion'].create(promotions) diff --git a/indoteknik_custom/models/sale_order.py b/indoteknik_custom/models/sale_order.py index b22ee2ee..7ccc551b 100755 --- a/indoteknik_custom/models/sale_order.py +++ b/indoteknik_custom/models/sale_order.py @@ -450,10 +450,11 @@ class SaleOrder(models.Model): @api.depends('date_order', 'estimated_arrival_days', 'state', 'estimated_arrival_days_start') def _compute_eta_date(self): + current_date = datetime.now().date() for rec in self: if rec.date_order and rec.state not in ['cancel'] and rec.estimated_arrival_days and rec.estimated_arrival_days_start: - rec.eta_date = rec.date_order + timedelta(days=rec.estimated_arrival_days) - rec.eta_date_start = rec.date_order + timedelta(days=rec.estimated_arrival_days_start) + rec.eta_date = current_date + timedelta(days=rec.estimated_arrival_days) + rec.eta_date_start = current_date + timedelta(days=rec.estimated_arrival_days_start) else: rec.eta_date = False rec.eta_date_start = False @@ -527,22 +528,23 @@ class SaleOrder(models.Model): @api.depends("order_line.product_id") def _compute_etrts_date(self): #Function to calculate Estimated Ready To Ship Date - for rec in self: - max_slatime = 1 # Default SLA jika tidak ada - slatime = self.calculate_sla_by_vendor(rec.order_line) - max_slatime = max(max_slatime, slatime['slatime']) - - - current_date = datetime.now().date() - - if rec.date_order: - sum_days = max_slatime + self.get_days_until_next_business_day(current_date) - 1 - rec.estimated_arrival_days = sum_days + if self.order_line: + for rec in self: + max_slatime = 1 # Default SLA jika tidak ada + slatime = self.calculate_sla_by_vendor(rec.order_line) + max_slatime = max(max_slatime, slatime['slatime']) - eta_date = current_date + timedelta(days=sum_days) - rec.estimated_ready_ship_date = eta_date - rec.commitment_date = eta_date - rec.expected_ready_to_ship = eta_date + current_date = datetime.now().date() + + if rec.date_order: + sum_days = max_slatime + self.get_days_until_next_business_day(current_date) - 1 + if rec.source_id.name != 'Website': + rec.estimated_arrival_days = sum_days + + eta_date = current_date + timedelta(days=sum_days) + rec.estimated_ready_ship_date = eta_date + rec.commitment_date = eta_date + rec.expected_ready_to_ship = eta_date -- cgit v1.2.3 From fc5defa647bcdd317dc2d4069432c2dcc1141344 Mon Sep 17 00:00:00 2001 From: trisusilo48 Date: Wed, 19 Mar 2025 10:04:31 +0700 Subject: change mthode validation expected date --- indoteknik_custom/models/sale_order.py | 87 ++++++++++++++++++---------------- 1 file changed, 45 insertions(+), 42 deletions(-) diff --git a/indoteknik_custom/models/sale_order.py b/indoteknik_custom/models/sale_order.py index 7ccc551b..e2755eba 100755 --- a/indoteknik_custom/models/sale_order.py +++ b/indoteknik_custom/models/sale_order.py @@ -190,10 +190,10 @@ class SaleOrder(models.Model): ('PNR', 'Pareto Non Repeating'), ('NP', 'Non Pareto') ]) - estimated_ready_ship_date = fields.Datetime( - string='ET Ready to Ship compute', - compute='_compute_etrts_date' - ) + # estimated_ready_ship_date = fields.Datetime( + # string='ET Ready to Ship compute', + # compute='_compute_etrts_date' + # ) expected_ready_to_ship = fields.Datetime( string='ET Ready to Ship', copy=False, @@ -479,16 +479,6 @@ class SaleOrder(models.Model): break return offset - - # def calculate_sla_by_vendor(self, products): - # slatime = 15 - # for line in products: - # product_sla = self.env['product.sla'].search([('product_variant_id', '=', line.product_id.id)], limit=1) - # slatime = int(product_sla.sla) if product_sla and product_sla.sla and product_sla.sla != 'Indent' and "hari" in product_sla.sla.lower() else 15 - - # return { - # 'slatime' : slatime - # } def calculate_sla_by_vendor(self, products): product_ids = products.mapped('product_id.id') # Kumpulkan semua ID produk @@ -526,43 +516,55 @@ class SaleOrder(models.Model): return {'slatime': max_slatime, 'include_instant': include_instant} - @api.depends("order_line.product_id") + @api.depends("order_line.product_id", "date_order") def _compute_etrts_date(self): #Function to calculate Estimated Ready To Ship Date - if self.order_line: - for rec in self: - max_slatime = 1 # Default SLA jika tidak ada - slatime = self.calculate_sla_by_vendor(rec.order_line) - max_slatime = max(max_slatime, slatime['slatime']) - - current_date = datetime.now().date() + for rec in self: + if not rec.date_order: + rec.expected_ready_to_ship = False + return + + current_date = datetime.now().date() + + max_slatime = 1 # Default SLA jika tidak ada + slatime = self.calculate_sla_by_vendor(rec.order_line) + max_slatime = max(max_slatime, slatime['slatime']) - if rec.date_order: - sum_days = max_slatime + self.get_days_until_next_business_day(current_date) - 1 - if rec.source_id.name != 'Website': - rec.estimated_arrival_days = sum_days - - eta_date = current_date + timedelta(days=sum_days) - rec.estimated_ready_ship_date = eta_date - rec.commitment_date = eta_date - rec.expected_ready_to_ship = eta_date - - - - @api.onchange('expected_ready_to_ship') #Hangle Onchange form Expected Ready to Ship - def _onchange_expected_ready_ship_date(self): + sum_days = max_slatime + self.get_days_until_next_business_day(current_date) - 1 + if not rec.estimated_arrival_days: + rec.estimated_arrival_days = sum_days + + eta_date = current_date + timedelta(days=sum_days) + rec.commitment_date = eta_date + # Jika expected_ready_to_ship kosong, set nilai default + if not rec.expected_ready_to_ship: + rec.expected_ready_to_ship = eta_date + + def _validate_expected_ready_ship_date(self): for rec in self: - if rec.expected_ready_to_ship and rec.estimated_ready_ship_date: + if rec.expected_ready_to_ship and rec.commitment_date: + current_date = datetime.now().date() # Hanya membandingkan tanggal saja, tanpa jam expected_date = rec.expected_ready_to_ship.date() - estimated_date = rec.estimated_ready_ship_date.date() - if expected_date < estimated_date: - rec.expected_ready_to_ship = rec.estimated_ready_ship_date - rec.commitment_date = rec.estimated_ready_ship_date + max_slatime = 1 # Default SLA jika tidak ada + slatime = self.calculate_sla_by_vendor(rec.order_line) + max_slatime = max(max_slatime, slatime['slatime']) + sum_days = max_slatime + self.get_days_until_next_business_day(current_date) - 1 + eta_minimum = current_date + timedelta(days=sum_days) + + if expected_date < eta_minimum: + rec.expected_ready_to_ship = eta_minimum raise ValidationError( "Tanggal 'Expected Ready to Ship' tidak boleh lebih kecil dari {}. Mohon pilih tanggal minimal {}." - .format(estimated_date.strftime('%d-%m-%Y'), estimated_date.strftime('%d-%m-%Y')) + .format(eta_minimum.strftime('%d-%m-%Y'), eta_minimum.strftime('%d-%m-%Y')) ) + else: + rec.commitment_date = rec.expected_ready_to_ship + + + @api.onchange('expected_ready_to_ship') #Hangle Onchange form Expected Ready to Ship + def _onchange_expected_ready_ship_date(self): + self._validate_expected_ready_ship_date() def _set_etrts_date(self): for order in self: @@ -1623,6 +1625,7 @@ class SaleOrder(models.Model): # Ensure partner details are updated when a sale order is created order = super(SaleOrder, self).create(vals) order._compute_etrts_date() + order._validate_expected_ready_ship_date() # order._update_partner_details() return order -- cgit v1.2.3 From 4c8ff729c027654870b3cf71015e5c7ecec28a7b Mon Sep 17 00:00:00 2001 From: trisusilo48 Date: Wed, 19 Mar 2025 10:32:24 +0700 Subject: expected rts --- indoteknik_custom/models/sale_order.py | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/indoteknik_custom/models/sale_order.py b/indoteknik_custom/models/sale_order.py index acad7729..b17df045 100755 --- a/indoteknik_custom/models/sale_order.py +++ b/indoteknik_custom/models/sale_order.py @@ -545,9 +545,8 @@ class SaleOrder(models.Model): max_slatime = max(max_slatime, slatime) return {'slatime': max_slatime, 'include_instant': include_instant} - - @api.depends("order_line.product_id", "date_order") - def _compute_etrts_date(self): #Function to calculate Estimated Ready To Ship Date + + def _calculate_etrts_date(self): for rec in self: if not rec.date_order: rec.expected_ready_to_ship = False @@ -565,9 +564,12 @@ class SaleOrder(models.Model): eta_date = current_date + timedelta(days=sum_days) rec.commitment_date = eta_date - # Jika expected_ready_to_ship kosong, set nilai default - if not rec.expected_ready_to_ship: - rec.expected_ready_to_ship = eta_date + rec.expected_ready_to_ship = eta_date + + @api.depends("order_line.product_id", "date_order") + def _compute_etrts_date(self): #Function to calculate Estimated Ready To Ship Date + self._calculate_etrts_date() + def _validate_expected_ready_ship_date(self): for rec in self: @@ -1713,5 +1715,5 @@ class SaleOrder(models.Model): res = super(SaleOrder, self).write(vals) if any(field in vals for field in ["order_line", "client_order_ref"]): - self._compute_etrts_date() + self._calculate_etrts_date() return res \ No newline at end of file -- cgit v1.2.3