From 75fa42b4f5afb7a70e30c84b7a348f65e1bb99e9 Mon Sep 17 00:00:00 2001 From: Azka Nathan Date: Wed, 4 Dec 2024 14:08:32 +0700 Subject: api tracking envio --- indoteknik_custom/models/stock_picking.py | 115 +++++++++++++++++++++++++++++- 1 file changed, 112 insertions(+), 3 deletions(-) diff --git a/indoteknik_custom/models/stock_picking.py b/indoteknik_custom/models/stock_picking.py index 03b10cdb..0d8c6b0f 100644 --- a/indoteknik_custom/models/stock_picking.py +++ b/indoteknik_custom/models/stock_picking.py @@ -1,9 +1,11 @@ from odoo import fields, models, api, _ from odoo.exceptions import AccessError, UserError, ValidationError from odoo.tools.float_utils import float_is_zero -from datetime import datetime +from datetime import datetime, timedelta from itertools import groupby -import pytz, datetime, requests, json +import pytz, requests, json, requests +from dateutil import parser +# import datetime class StockPicking(models.Model): @@ -113,6 +115,113 @@ class StockPicking(models.Model): ], string='Status Reserve', readonly=True, tracking=True, help="The current state of the stock picking.") notee = fields.Text(string="Note") + # Envio Tracking Section + envio_id = fields.Char(string="Envio ID", readonly=True) + envio_code = fields.Char(string="Envio Code", readonly=True) + envio_ref_code = fields.Char(string="Envio Reference Code", readonly=True) + envio_eta_at = fields.Char(string="Estimated Time of Arrival (ETA)", readonly=True) + envio_ata_at = fields.Char(string="Actual Time of Arrival (ATA)", readonly=True) + envio_etd_at = fields.Char(string="Estimated Time of Departure (ETD)", readonly=True) + envio_atd_at = fields.Char(string="Actual Time of Departure (ATD)", readonly=True) + envio_received_by = fields.Char(string="Received By", readonly=True) + envio_status = fields.Char(string="Status", readonly=True) + envio_cod_value = fields.Float(string="COD Value", readonly=True) + envio_cod_status = fields.Char(string="COD Status", readonly=True) + envio_logs = fields.Text(string="Logs", readonly=True) + envio_latest_message = fields.Text(string="Latest Log Message", readonly=True) + envio_latest_recorded_at = fields.Char(string="Log Recorded At", readonly=True) + envio_latest_latitude = fields.Float(string="Log Latitude", readonly=True) + envio_latest_longitude = fields.Float(string="Log Longitude", readonly=True) + tracking_by = fields.Many2one('res.users', string='Tracking By', readonly=True, tracking=True) + + def _convert_to_wib(self, date_str): + """ + Mengonversi string waktu ISO 8601 ke format waktu Indonesia (WIB) + """ + if not date_str: + return False + try: + utc_time = datetime.strptime(date_str, '%Y-%m-%dT%H:%M:%SZ') + wib_time = utc_time + timedelta(hours=7) + return wib_time.strftime('%d-%m-%Y %H:%M:%S') + except ValueError: + raise UserError(f"Format waktu tidak sesuai: {date_str}") + + def _convert_to_datetime(self, date_str): + """Mengonversi string waktu dari API ke datetime.""" + if not date_str: + return False + try: + # Format waktu dengan milidetik + return datetime.strptime(date_str, '%Y-%m-%dT%H:%M:%S.%fZ') + except ValueError: + try: + # Format waktu tanpa milidetik + return datetime.strptime(date_str, '%Y-%m-%dT%H:%M:%SZ') + except ValueError: + raise UserError(f"Format waktu tidak sesuai: {date_str}") + + def track_envio_shipment(self): + pickings = self.env['stock.picking'].search([ + ('picking_type_code', '=', 'outgoing'), + ('state', '=', 'done'), + ('carrier_id', '=', 151) + ]) + for picking in pickings: + if not picking.name: + raise UserError("Name pada stock.picking tidak ditemukan.") + + # API URL dan headers + url = f"https://api.envio.co.id/v1/tracking/distribution?code={picking.name}" + headers = { + 'Authorization': 'Bearer JZ0Seh6qpYJAC3CJHdhF7sPqv8B/uSSfZe1VX5BL?vPYdo', + 'Content-Type': 'application/json', + } + + try: + # Request ke API + response = requests.get(url, headers=headers, timeout=10) + response.raise_for_status() # Raise error jika status code bukan 200 + response_data = response.json() + + # Validasi jika respons tidak sesuai format yang diharapkan + if not response_data or "data" not in response_data: + raise UserError("Respons API tidak sesuai format yang diharapkan.") + + data = response_data.get("data") + if not data: + continue + + # Menyimpan data ke field masing-masing + picking.envio_id = data.get("id") + picking.envio_code = data.get("code") + picking.envio_ref_code = data.get("ref_code") + picking.envio_eta_at = self._convert_to_datetime(data.get("eta_at")) + picking.envio_ata_at = self._convert_to_datetime(data.get("ata_at")) + picking.envio_etd_at = self._convert_to_datetime(data.get("etd_at")) + picking.envio_atd_at = self._convert_to_datetime(data.get("atd_at")) + picking.envio_received_by = data.get("received_by") + picking.envio_status = data.get("status") + picking.envio_cod_value = data.get("cod_value", 0.0) + picking.envio_cod_status = data.get("cod_status") + + # Menyimpan log terbaru + logs = data.get("logs", []) + if logs and isinstance(logs, list) and logs[0]: + latest_log = logs[0] + picking.envio_latest_message = latest_log.get("message", "Log kosong.") + picking.envio_latest_recorded_at = self._convert_to_datetime(latest_log.get("recorded_at")) + picking.envio_latest_latitude = latest_log.get("latitude", 0.0) + picking.envio_latest_longitude = latest_log.get("longitude", 0.0) + + picking.tracking_by = self.env.user.id + ata_at_str = data.get("ata_at") + picking.driver_arrival_date = self._convert_to_datetime(ata_at_str) if ata_at_str else False + except requests.exceptions.RequestException as e: + raise UserError(f"Terjadi kesalahan saat menghubungi API Envio: {str(e)}") + except Exception as e: + raise UserError(f"Kesalahan tidak terduga: {str(e)}") + def action_send_to_biteship(self): url = "https://api.biteship.com/v1/orders" api_key = "biteship_test.eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYW1lIjoiSW5kb3Rla25payIsInVzZXJJZCI6IjY3MTViYTJkYzVkMjdkMDAxMjRjODk2MiIsImlhdCI6MTcyOTQ5ODAwMX0.L6C73couP4-cgVEfhKI2g7eMCMo3YOFSRZhS-KSuHNA" @@ -539,7 +648,7 @@ class StockPicking(models.Model): qty_onhand = check_qty_per_inventory(self, line.product_id, line.location_id) if line.qty_done > qty_onhand: - raise UserError(f'{line.product_id.display_name} : Quantity Done melebihi Quantity Onhand') + raise UserError('Quantity Done melebihi Quantity Onhand') def button_validate(self): if not self.env.user.is_logistic_approver and self.env.context.get('active_model') == 'stock.picking': -- cgit v1.2.3 From 9b4ee2c98ca1537282b6ce9a0aff5c556d2be5a9 Mon Sep 17 00:00:00 2001 From: Azka Nathan Date: Wed, 4 Dec 2024 14:08:57 +0700 Subject: api tracking envio --- indoteknik_custom/views/stock_picking.xml | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/indoteknik_custom/views/stock_picking.xml b/indoteknik_custom/views/stock_picking.xml index 1893fcaf..562be8d9 100644 --- a/indoteknik_custom/views/stock_picking.xml +++ b/indoteknik_custom/views/stock_picking.xml @@ -56,6 +56,11 @@ string="Biteship" type="object" /> + @@ -143,6 +148,24 @@ + + + + + + + + + + + + + + + + + + -- cgit v1.2.3 From c60a7a4b0844fe04ec29656b185b9fa80d398c26 Mon Sep 17 00:00:00 2001 From: stephanchrst Date: Wed, 4 Dec 2024 14:10:10 +0700 Subject: add validation mandatory category --- indoteknik_custom/models/product_template.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/indoteknik_custom/models/product_template.py b/indoteknik_custom/models/product_template.py index 4d186568..6fb8c7a0 100755 --- a/indoteknik_custom/models/product_template.py +++ b/indoteknik_custom/models/product_template.py @@ -66,7 +66,7 @@ class ProductTemplate(models.Model): @api.constrains('name', 'internal_reference', 'x_manufacture') def required_public_categ_ids(self): for rec in self: - if not rec.public_categ_ids: + if not rec.public_categ_ids and rec.type == 'product': raise UserError('Field Categories harus diisi') def _get_qty_sold(self): @@ -388,7 +388,7 @@ class ProductProduct(models.Model): @api.constrains('name', 'internal_reference', 'x_manufacture') def required_public_categ_ids(self): for rec in self: - if not rec.public_categ_ids: + if not rec.public_categ_ids and rec.type == 'product': raise UserError('Field Categories harus diisi') @api.constrains('active') -- cgit v1.2.3 From 61cfbef8ec24ca67c9a65b7901bb9ec615364977 Mon Sep 17 00:00:00 2001 From: Azka Nathan Date: Wed, 4 Dec 2024 14:20:40 +0700 Subject: fix error --- indoteknik_custom/models/stock_picking.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/indoteknik_custom/models/stock_picking.py b/indoteknik_custom/models/stock_picking.py index 0d8c6b0f..0da258e5 100644 --- a/indoteknik_custom/models/stock_picking.py +++ b/indoteknik_custom/models/stock_picking.py @@ -5,7 +5,7 @@ from datetime import datetime, timedelta from itertools import groupby import pytz, requests, json, requests from dateutil import parser -# import datetime +import datetime class StockPicking(models.Model): -- cgit v1.2.3 From 65a1d7c8fb4e4bd3b055efec5362d98a2d4340fc Mon Sep 17 00:00:00 2001 From: Azka Nathan Date: Wed, 4 Dec 2024 14:27:53 +0700 Subject: test api envio --- indoteknik_custom/models/stock_picking.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/indoteknik_custom/models/stock_picking.py b/indoteknik_custom/models/stock_picking.py index 0da258e5..327a4223 100644 --- a/indoteknik_custom/models/stock_picking.py +++ b/indoteknik_custom/models/stock_picking.py @@ -167,7 +167,7 @@ class StockPicking(models.Model): ('state', '=', 'done'), ('carrier_id', '=', 151) ]) - for picking in pickings: + for picking in self: if not picking.name: raise UserError("Name pada stock.picking tidak ditemukan.") -- cgit v1.2.3 From 4eac4d0709ec5d9e03b517a39cb67acbc35e2932 Mon Sep 17 00:00:00 2001 From: Azka Nathan Date: Wed, 4 Dec 2024 14:43:55 +0700 Subject: fix bug --- indoteknik_custom/models/stock_picking.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/indoteknik_custom/models/stock_picking.py b/indoteknik_custom/models/stock_picking.py index 327a4223..931da588 100644 --- a/indoteknik_custom/models/stock_picking.py +++ b/indoteknik_custom/models/stock_picking.py @@ -1,7 +1,7 @@ from odoo import fields, models, api, _ from odoo.exceptions import AccessError, UserError, ValidationError from odoo.tools.float_utils import float_is_zero -from datetime import datetime, timedelta +from datetime import timedelta from itertools import groupby import pytz, requests, json, requests from dateutil import parser -- cgit v1.2.3 From 4d5a0a6e2d997e323f8670172226f613b7673d62 Mon Sep 17 00:00:00 2001 From: trisusilo48 Date: Thu, 5 Dec 2024 14:47:20 +0700 Subject: convert iamge to webp extension --- indoteknik_api/controllers/controller.py | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/indoteknik_api/controllers/controller.py b/indoteknik_api/controllers/controller.py index a34a2688..0f20d319 100644 --- a/indoteknik_api/controllers/controller.py +++ b/indoteknik_api/controllers/controller.py @@ -4,6 +4,7 @@ import functools import io import json from array import array +from io import BytesIO import jwt from odoo import http @@ -11,6 +12,8 @@ from odoo.http import request from odoo.modules import get_module_resource from odoo.tools.config import config from PIL import Image +from PIL.WebPImagePlugin import Image +from PIL import features from pytz import timezone @@ -204,6 +207,8 @@ class Controller(http.Controller): if not variant: image = self.add_watermark_to_image(image, ratio, version) + image = self.convert_to_webp(image) + response_headers = [ ('Content-Type', 'image/jpg'), ('Cache-Control', 'public, max-age=3600') @@ -214,6 +219,31 @@ class Controller(http.Controller): response_headers ) + def convert_to_webp(self, image_base64): + """Convert image from base64 to WebP format and return base64 WebP.""" + try: + print(f"Image base64 length: {len(image_base64)}") + + # Decode Base64 to Bytes + image_data = base64.b64decode(image_base64) + image = Image.open(BytesIO(image_data)) + + if image.mode in ("RGBA", "P"): # Cek alpha channel atau palet + image = image.convert("RGB") # Konversi ke RGB + + # Convert to WebP + with BytesIO() as output: + image.save(output, format="WEBP", quality=85) + webp_data = output.getvalue() + + # Encode back to Base64 + return base64.b64encode(webp_data).decode('utf-8') + except Exception as e: + print(f"Error details: {e}") + # If conversion fails, return the original image + request.env.cr.rollback() # Rollback any transactions + return image_base64 + def add_watermark_to_image(self, image, ratio, version = '1'): if not image: return '' -- cgit v1.2.3 From 4fa79ffd236f76ace6525b67031f3a3e9af729c1 Mon Sep 17 00:00:00 2001 From: trisusilo48 Date: Thu, 5 Dec 2024 15:41:43 +0700 Subject: fixing format --- indoteknik_api/controllers/controller.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/indoteknik_api/controllers/controller.py b/indoteknik_api/controllers/controller.py index 0f20d319..26f0e3e4 100644 --- a/indoteknik_api/controllers/controller.py +++ b/indoteknik_api/controllers/controller.py @@ -228,9 +228,6 @@ class Controller(http.Controller): image_data = base64.b64decode(image_base64) image = Image.open(BytesIO(image_data)) - if image.mode in ("RGBA", "P"): # Cek alpha channel atau palet - image = image.convert("RGB") # Konversi ke RGB - # Convert to WebP with BytesIO() as output: image.save(output, format="WEBP", quality=85) -- cgit v1.2.3 From 187a5463b08f57f944afd80ee6b8d38047661ca0 Mon Sep 17 00:00:00 2001 From: trisusilo48 Date: Thu, 5 Dec 2024 15:48:53 +0700 Subject: hold conver to webp --- indoteknik_api/controllers/controller.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/indoteknik_api/controllers/controller.py b/indoteknik_api/controllers/controller.py index 26f0e3e4..f777dba8 100644 --- a/indoteknik_api/controllers/controller.py +++ b/indoteknik_api/controllers/controller.py @@ -207,7 +207,7 @@ class Controller(http.Controller): if not variant: image = self.add_watermark_to_image(image, ratio, version) - image = self.convert_to_webp(image) + # image = self.convert_to_webp(image) response_headers = [ ('Content-Type', 'image/jpg'), -- cgit v1.2.3 From 4721464cf2cd6d9c331b7ecc3ceaab5a6548b7c9 Mon Sep 17 00:00:00 2001 From: Azka Nathan Date: Thu, 5 Dec 2024 15:54:03 +0700 Subject: fix bug --- indoteknik_api/controllers/controller.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/indoteknik_api/controllers/controller.py b/indoteknik_api/controllers/controller.py index f777dba8..b7bf5f71 100644 --- a/indoteknik_api/controllers/controller.py +++ b/indoteknik_api/controllers/controller.py @@ -12,7 +12,7 @@ from odoo.http import request from odoo.modules import get_module_resource from odoo.tools.config import config from PIL import Image -from PIL.WebPImagePlugin import Image +# from PIL.WebPImagePlugin import Image from PIL import features from pytz import timezone -- cgit v1.2.3 From 32a33b7ef6c61424bc9785bdb4246a9be58e5b42 Mon Sep 17 00:00:00 2001 From: Azka Nathan Date: Thu, 5 Dec 2024 16:10:09 +0700 Subject: fix bug api envio --- indoteknik_custom/models/stock_picking.py | 29 ++++++++++++++++++----------- 1 file changed, 18 insertions(+), 11 deletions(-) diff --git a/indoteknik_custom/models/stock_picking.py b/indoteknik_custom/models/stock_picking.py index 931da588..6d911470 100644 --- a/indoteknik_custom/models/stock_picking.py +++ b/indoteknik_custom/models/stock_picking.py @@ -1,7 +1,7 @@ from odoo import fields, models, api, _ from odoo.exceptions import AccessError, UserError, ValidationError from odoo.tools.float_utils import float_is_zero -from datetime import timedelta +from datetime import timedelta, datetime from itertools import groupby import pytz, requests, json, requests from dateutil import parser @@ -119,17 +119,17 @@ class StockPicking(models.Model): envio_id = fields.Char(string="Envio ID", readonly=True) envio_code = fields.Char(string="Envio Code", readonly=True) envio_ref_code = fields.Char(string="Envio Reference Code", readonly=True) - envio_eta_at = fields.Char(string="Estimated Time of Arrival (ETA)", readonly=True) - envio_ata_at = fields.Char(string="Actual Time of Arrival (ATA)", readonly=True) - envio_etd_at = fields.Char(string="Estimated Time of Departure (ETD)", readonly=True) - envio_atd_at = fields.Char(string="Actual Time of Departure (ATD)", readonly=True) + envio_eta_at = fields.Datetime(string="Estimated Time of Arrival (ETA)", readonly=True) + envio_ata_at = fields.Datetime(string="Actual Time of Arrival (ATA)", readonly=True) + envio_etd_at = fields.Datetime(string="Estimated Time of Departure (ETD)", readonly=True) + envio_atd_at = fields.Datetime(string="Actual Time of Departure (ATD)", readonly=True) envio_received_by = fields.Char(string="Received By", readonly=True) envio_status = fields.Char(string="Status", readonly=True) envio_cod_value = fields.Float(string="COD Value", readonly=True) envio_cod_status = fields.Char(string="COD Status", readonly=True) envio_logs = fields.Text(string="Logs", readonly=True) envio_latest_message = fields.Text(string="Latest Log Message", readonly=True) - envio_latest_recorded_at = fields.Char(string="Log Recorded At", readonly=True) + envio_latest_recorded_at = fields.Datetime(string="Log Recorded At", readonly=True) envio_latest_latitude = fields.Float(string="Log Latitude", readonly=True) envio_latest_longitude = fields.Float(string="Log Longitude", readonly=True) tracking_by = fields.Many2one('res.users', string='Tracking By', readonly=True, tracking=True) @@ -141,7 +141,7 @@ class StockPicking(models.Model): if not date_str: return False try: - utc_time = datetime.strptime(date_str, '%Y-%m-%dT%H:%M:%SZ') + utc_time = datetime.datetime.strptime(date_str, '%Y-%m-%dT%H:%M:%SZ') wib_time = utc_time + timedelta(hours=7) return wib_time.strftime('%d-%m-%Y %H:%M:%S') except ValueError: @@ -153,11 +153,13 @@ class StockPicking(models.Model): return False try: # Format waktu dengan milidetik - return datetime.strptime(date_str, '%Y-%m-%dT%H:%M:%S.%fZ') + date = datetime.datetime.strptime(date_str, '%Y-%m-%dT%H:%M:%S.%fZ') + return date except ValueError: try: # Format waktu tanpa milidetik - return datetime.strptime(date_str, '%Y-%m-%dT%H:%M:%SZ') + date = datetime.datetime.strptime(date_str, '%Y-%m-%dT%H:%M:%SZ') + return date except ValueError: raise UserError(f"Format waktu tidak sesuai: {date_str}") @@ -167,7 +169,7 @@ class StockPicking(models.Model): ('state', '=', 'done'), ('carrier_id', '=', 151) ]) - for picking in self: + for picking in pickings: if not picking.name: raise UserError("Name pada stock.picking tidak ditemukan.") @@ -216,7 +218,12 @@ class StockPicking(models.Model): picking.tracking_by = self.env.user.id ata_at_str = data.get("ata_at") - picking.driver_arrival_date = self._convert_to_datetime(ata_at_str) if ata_at_str else False + envio_ata = self._convert_to_datetime(data.get("ata_at")) + + picking.driver_arrival_date = envio_ata + if data.get("status") == 'returned': + picking.driver_arrival_date = False + picking.envio_ata_at = False except requests.exceptions.RequestException as e: raise UserError(f"Terjadi kesalahan saat menghubungi API Envio: {str(e)}") except Exception as e: -- cgit v1.2.3 From 4daa1f70f7f390831c1b64f054f93fe3be81eebe Mon Sep 17 00:00:00 2001 From: trisusilo48 Date: Thu, 5 Dec 2024 16:30:30 +0700 Subject: fixing convert image --- indoteknik_api/controllers/controller.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/indoteknik_api/controllers/controller.py b/indoteknik_api/controllers/controller.py index f777dba8..80f45074 100644 --- a/indoteknik_api/controllers/controller.py +++ b/indoteknik_api/controllers/controller.py @@ -228,6 +228,9 @@ class Controller(http.Controller): image_data = base64.b64decode(image_base64) image = Image.open(BytesIO(image_data)) + if image.format == "PNG" and image.mode != "RGBA": + image = image.convert("RGBA") + # Convert to WebP with BytesIO() as output: image.save(output, format="WEBP", quality=85) -- cgit v1.2.3 From 19abaad4eb47443e621108985c0d0dcf2d4c6609 Mon Sep 17 00:00:00 2001 From: trisusilo48 Date: Thu, 5 Dec 2024 16:32:15 +0700 Subject: ketinggalan --- indoteknik_api/controllers/controller.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/indoteknik_api/controllers/controller.py b/indoteknik_api/controllers/controller.py index ebabfd03..7f49c4e5 100644 --- a/indoteknik_api/controllers/controller.py +++ b/indoteknik_api/controllers/controller.py @@ -207,7 +207,7 @@ class Controller(http.Controller): if not variant: image = self.add_watermark_to_image(image, ratio, version) - # image = self.convert_to_webp(image) + image = self.convert_to_webp(image) response_headers = [ ('Content-Type', 'image/jpg'), -- cgit v1.2.3 From 3771d33ddb1abf2ffe434d71bd1dbeadcb83c00d Mon Sep 17 00:00:00 2001 From: Azka Nathan Date: Fri, 6 Dec 2024 09:01:32 +0700 Subject: fix bug --- indoteknik_custom/models/stock_picking.py | 69 +++++++++++++++---------------- 1 file changed, 33 insertions(+), 36 deletions(-) diff --git a/indoteknik_custom/models/stock_picking.py b/indoteknik_custom/models/stock_picking.py index 6d911470..37e43054 100644 --- a/indoteknik_custom/models/stock_picking.py +++ b/indoteknik_custom/models/stock_picking.py @@ -169,11 +169,11 @@ class StockPicking(models.Model): ('state', '=', 'done'), ('carrier_id', '=', 151) ]) + for picking in pickings: if not picking.name: raise UserError("Name pada stock.picking tidak ditemukan.") - # API URL dan headers url = f"https://api.envio.co.id/v1/tracking/distribution?code={picking.name}" headers = { 'Authorization': 'Bearer JZ0Seh6qpYJAC3CJHdhF7sPqv8B/uSSfZe1VX5BL?vPYdo', @@ -181,53 +181,50 @@ class StockPicking(models.Model): } try: - # Request ke API response = requests.get(url, headers=headers, timeout=10) - response.raise_for_status() # Raise error jika status code bukan 200 + response.raise_for_status() response_data = response.json() - # Validasi jika respons tidak sesuai format yang diharapkan - if not response_data or "data" not in response_data: - raise UserError("Respons API tidak sesuai format yang diharapkan.") - data = response_data.get("data") if not data: continue - # Menyimpan data ke field masing-masing - picking.envio_id = data.get("id") - picking.envio_code = data.get("code") - picking.envio_ref_code = data.get("ref_code") - picking.envio_eta_at = self._convert_to_datetime(data.get("eta_at")) - picking.envio_ata_at = self._convert_to_datetime(data.get("ata_at")) - picking.envio_etd_at = self._convert_to_datetime(data.get("etd_at")) - picking.envio_atd_at = self._convert_to_datetime(data.get("atd_at")) - picking.envio_received_by = data.get("received_by") - picking.envio_status = data.get("status") - picking.envio_cod_value = data.get("cod_value", 0.0) - picking.envio_cod_status = data.get("cod_status") - - # Menyimpan log terbaru - logs = data.get("logs", []) - if logs and isinstance(logs, list) and logs[0]: - latest_log = logs[0] - picking.envio_latest_message = latest_log.get("message", "Log kosong.") - picking.envio_latest_recorded_at = self._convert_to_datetime(latest_log.get("recorded_at")) - picking.envio_latest_latitude = latest_log.get("latitude", 0.0) - picking.envio_latest_longitude = latest_log.get("longitude", 0.0) - + # Mapping field dengan data API + fields_map = { + 'envio_id': "id", + 'envio_code': "code", + 'envio_ref_code': "ref_code", + 'envio_eta_at': "eta_at", + 'envio_ata_at': "ata_at", + 'envio_etd_at': "etd_at", + 'envio_atd_at': "atd_at", + 'envio_received_by': "received_by", + 'envio_status': "status", + 'envio_cod_value': "cod_value", + 'envio_cod_status': "cod_status", + } + + for field, key in fields_map.items(): + setattr(picking, field, data.get(key, 0.0 if 'cod' in key else False)) + + # Menyimpan log terbaru jika ada + latest_log = (data.get("logs") or [{}])[0] + picking.envio_latest_message = latest_log.get("message", "Log kosong.") + picking.envio_latest_recorded_at = self._convert_to_datetime(latest_log.get("recorded_at")) + picking.envio_latest_latitude = latest_log.get("latitude", 0.0) + picking.envio_latest_longitude = latest_log.get("longitude", 0.0) + + # Menyimpan data tambahan picking.tracking_by = self.env.user.id - ata_at_str = data.get("ata_at") envio_ata = self._convert_to_datetime(data.get("ata_at")) + picking.driver_arrival_date = envio_ata if envio_ata != '0001-01-01 00:00:00' else False + picking.envio_ata_at = envio_ata if envio_ata != '0001-01-01 00:00:00' else False - picking.driver_arrival_date = envio_ata - if data.get("status") == 'returned': - picking.driver_arrival_date = False - picking.envio_ata_at = False except requests.exceptions.RequestException as e: - raise UserError(f"Terjadi kesalahan saat menghubungi API Envio: {str(e)}") + raise UserError(f"Terjadi kesalahan saat menghubungi API Envio: {e}") except Exception as e: - raise UserError(f"Kesalahan tidak terduga: {str(e)}") + raise UserError(f"Kesalahan tidak terduga: {e}") + def action_send_to_biteship(self): url = "https://api.biteship.com/v1/orders" -- cgit v1.2.3 From 16f2140b7ce089cb417acd1093364fd8c6b51513 Mon Sep 17 00:00:00 2001 From: trisusilo48 Date: Fri, 6 Dec 2024 10:17:23 +0700 Subject: add lib webp --- indoteknik_api/controllers/controller.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/indoteknik_api/controllers/controller.py b/indoteknik_api/controllers/controller.py index 7f49c4e5..81cea9ff 100644 --- a/indoteknik_api/controllers/controller.py +++ b/indoteknik_api/controllers/controller.py @@ -12,7 +12,7 @@ from odoo.http import request from odoo.modules import get_module_resource from odoo.tools.config import config from PIL import Image -# from PIL.WebPImagePlugin import Image +from PIL.WebPImagePlugin import Image from PIL import features from pytz import timezone -- cgit v1.2.3 From b0e71c613a80283a76371a468d54771b284205b5 Mon Sep 17 00:00:00 2001 From: Azka Nathan Date: Fri, 6 Dec 2024 11:27:03 +0700 Subject: fix bug envio --- indoteknik_api/controllers/controller.py | 2 +- indoteknik_custom/models/stock_picking.py | 69 ++++++++++++++++--------------- 2 files changed, 37 insertions(+), 34 deletions(-) diff --git a/indoteknik_api/controllers/controller.py b/indoteknik_api/controllers/controller.py index 7f49c4e5..ebabfd03 100644 --- a/indoteknik_api/controllers/controller.py +++ b/indoteknik_api/controllers/controller.py @@ -207,7 +207,7 @@ class Controller(http.Controller): if not variant: image = self.add_watermark_to_image(image, ratio, version) - image = self.convert_to_webp(image) + # image = self.convert_to_webp(image) response_headers = [ ('Content-Type', 'image/jpg'), diff --git a/indoteknik_custom/models/stock_picking.py b/indoteknik_custom/models/stock_picking.py index 37e43054..e6506a0b 100644 --- a/indoteknik_custom/models/stock_picking.py +++ b/indoteknik_custom/models/stock_picking.py @@ -169,11 +169,11 @@ class StockPicking(models.Model): ('state', '=', 'done'), ('carrier_id', '=', 151) ]) - for picking in pickings: if not picking.name: raise UserError("Name pada stock.picking tidak ditemukan.") + # API URL dan headers url = f"https://api.envio.co.id/v1/tracking/distribution?code={picking.name}" headers = { 'Authorization': 'Bearer JZ0Seh6qpYJAC3CJHdhF7sPqv8B/uSSfZe1VX5BL?vPYdo', @@ -181,50 +181,53 @@ class StockPicking(models.Model): } try: + # Request ke API response = requests.get(url, headers=headers, timeout=10) - response.raise_for_status() + response.raise_for_status() # Raise error jika status code bukan 200 response_data = response.json() + # Validasi jika respons tidak sesuai format yang diharapkan + if not response_data or "data" not in response_data: + raise UserError("Respons API tidak sesuai format yang diharapkan.") + data = response_data.get("data") if not data: continue - # Mapping field dengan data API - fields_map = { - 'envio_id': "id", - 'envio_code': "code", - 'envio_ref_code': "ref_code", - 'envio_eta_at': "eta_at", - 'envio_ata_at': "ata_at", - 'envio_etd_at': "etd_at", - 'envio_atd_at': "atd_at", - 'envio_received_by': "received_by", - 'envio_status': "status", - 'envio_cod_value': "cod_value", - 'envio_cod_status': "cod_status", - } - - for field, key in fields_map.items(): - setattr(picking, field, data.get(key, 0.0 if 'cod' in key else False)) - - # Menyimpan log terbaru jika ada - latest_log = (data.get("logs") or [{}])[0] - picking.envio_latest_message = latest_log.get("message", "Log kosong.") - picking.envio_latest_recorded_at = self._convert_to_datetime(latest_log.get("recorded_at")) - picking.envio_latest_latitude = latest_log.get("latitude", 0.0) - picking.envio_latest_longitude = latest_log.get("longitude", 0.0) - - # Menyimpan data tambahan + # Menyimpan data ke field masing-masing + picking.envio_id = data.get("id") + picking.envio_code = data.get("code") + picking.envio_ref_code = data.get("ref_code") + picking.envio_eta_at = self._convert_to_datetime(data.get("eta_at")) + picking.envio_ata_at = self._convert_to_datetime(data.get("ata_at")) + picking.envio_etd_at = self._convert_to_datetime(data.get("etd_at")) + picking.envio_atd_at = self._convert_to_datetime(data.get("atd_at")) + picking.envio_received_by = data.get("received_by") + picking.envio_status = data.get("status") + picking.envio_cod_value = data.get("cod_value", 0.0) + picking.envio_cod_status = data.get("cod_status") + + # Menyimpan log terbaru + logs = data.get("logs", []) + if logs and isinstance(logs, list) and logs[0]: + latest_log = logs[0] + picking.envio_latest_message = latest_log.get("message", "Log kosong.") + picking.envio_latest_recorded_at = self._convert_to_datetime(latest_log.get("recorded_at")) + picking.envio_latest_latitude = latest_log.get("latitude", 0.0) + picking.envio_latest_longitude = latest_log.get("longitude", 0.0) + picking.tracking_by = self.env.user.id + ata_at_str = data.get("ata_at") envio_ata = self._convert_to_datetime(data.get("ata_at")) - picking.driver_arrival_date = envio_ata if envio_ata != '0001-01-01 00:00:00' else False - picking.envio_ata_at = envio_ata if envio_ata != '0001-01-01 00:00:00' else False + picking.driver_arrival_date = envio_ata + if data.get("status") != 'delivered': + picking.driver_arrival_date = False + picking.envio_ata_at = False except requests.exceptions.RequestException as e: - raise UserError(f"Terjadi kesalahan saat menghubungi API Envio: {e}") + raise UserError(f"Terjadi kesalahan saat menghubungi API Envio: {str(e)}") except Exception as e: - raise UserError(f"Kesalahan tidak terduga: {e}") - + raise UserError(f"Kesalahan tidak terduga: {str(e)}") def action_send_to_biteship(self): url = "https://api.biteship.com/v1/orders" -- cgit v1.2.3 From cb49fc4e0d1f8995626dbf2a12b5b29c67b98156 Mon Sep 17 00:00:00 2001 From: trisusilo48 Date: Mon, 9 Dec 2024 08:54:26 +0700 Subject: update state id if null --- indoteknik_api/models/res_users.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/indoteknik_api/models/res_users.py b/indoteknik_api/models/res_users.py index 52a044dc..77aeeef7 100644 --- a/indoteknik_api/models/res_users.py +++ b/indoteknik_api/models/res_users.py @@ -72,7 +72,7 @@ class ResUsers(models.Model): data['state_id'] = { 'id': user.state_id.id, 'name': user.state_id.name - } or None + } or 0 if user.kota_id: data['city'] = { -- cgit v1.2.3 From 7ae86bcd136fcd3aebbaf9bb483ee474d2a19c0c Mon Sep 17 00:00:00 2001 From: Azka Nathan Date: Mon, 9 Dec 2024 11:20:50 +0700 Subject: cr retur stock picking --- indoteknik_custom/models/stock_picking_return.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/indoteknik_custom/models/stock_picking_return.py b/indoteknik_custom/models/stock_picking_return.py index 91a3a9fd..d4347235 100644 --- a/indoteknik_custom/models/stock_picking_return.py +++ b/indoteknik_custom/models/stock_picking_return.py @@ -14,14 +14,14 @@ class ReturnPicking(models.TransientModel): ('id', '=', res['picking_id']), ]) - sale_id = stock_picking.group_id.sale_id - if not stock_picking.approval_return_status == 'approved' and sale_id.invoice_ids: + # sale_id = stock_picking.group_id.sale_id + if not stock_picking.approval_return_status == 'approved': raise UserError('Harus Approval Accounting AR untuk melakukan Retur') - purchase = self.env['purchase.order'].search([ - ('name', '=', stock_picking.group_id.name), - ]) - if not stock_picking.approval_return_status == 'approved' and purchase.invoice_ids: - raise UserError('Harus Approval Accounting AP untuk melakukan Retur') + # purchase = self.env['purchase.order'].search([ + # ('name', '=', stock_picking.group_id.name), + # ]) + # if not stock_picking.approval_return_status == 'approved' and purchase.invoice_ids: + # raise UserError('Harus Approval Accounting AP untuk melakukan Retur') return res \ No newline at end of file -- cgit v1.2.3 From 9dbae80871e94f439ea1b6c3cf6a13cab9221532 Mon Sep 17 00:00:00 2001 From: Azka Nathan Date: Tue, 10 Dec 2024 10:27:44 +0700 Subject: barcode product --- indoteknik_custom/models/product_template.py | 43 +++++++++++++++++++++++++++- indoteknik_custom/models/stock_move.py | 12 ++++++++ indoteknik_custom/views/product_template.xml | 6 ++++ indoteknik_custom/views/stock_picking.xml | 1 + 4 files changed, 61 insertions(+), 1 deletion(-) diff --git a/indoteknik_custom/models/product_template.py b/indoteknik_custom/models/product_template.py index 6fb8c7a0..ebf81811 100755 --- a/indoteknik_custom/models/product_template.py +++ b/indoteknik_custom/models/product_template.py @@ -5,7 +5,9 @@ import logging import requests import json import re +import qrcode, base64 from bs4 import BeautifulSoup +from io import BytesIO _logger = logging.getLogger(__name__) @@ -58,10 +60,30 @@ class ProductTemplate(models.Model): ('sp', 'Spare Part'), ('acc', 'Accessories') ], string='Kind of', copy=False) - sni = fields.Boolean(string='SNI') + sni = fields.Boolean(string='SNI') tkdn = fields.Boolean(string='TKDN') short_spesification = fields.Char(string='Short Spesification') merchandise_ok = fields.Boolean(string='Product Promotion') + print_barcode = fields.Boolean(string='Print Barcode', default="True") + qr_code = fields.Binary("QR Code", compute='_compute_qr_code') + + def _compute_qr_code(self): + for rec in self.product_variant_ids: + qr = qrcode.QRCode( + version=1, + error_correction=qrcode.constants.ERROR_CORRECT_L, + box_size=5, + border=4, + ) + qr.add_data(rec.display_name) + qr.make(fit=True) + img = qr.make_image(fill_color="black", back_color="white") + + buffer = BytesIO() + img.save(buffer, format="PNG") + qr_code_img = base64.b64encode(buffer.getvalue()).decode() + + rec.qr_code = qr_code_img @api.constrains('name', 'internal_reference', 'x_manufacture') def required_public_categ_ids(self): @@ -379,6 +401,25 @@ class ProductProduct(models.Model): qty_rpo = fields.Float(string='Qty RPO', compute='_get_qty_rpo') plafon_qty = fields.Float(string='Max Plafon', compute='_get_plafon_qty_product') merchandise_ok = fields.Boolean(string='Product Promotion') + qr_code_variant = fields.Binary("QR Code Variant", compute='_compute_qr_code_variant') + + def _compute_qr_code_variant(self): + for rec in self.product_variant_ids: + qr = qrcode.QRCode( + version=1, + error_correction=qrcode.constants.ERROR_CORRECT_L, + box_size=5, + border=4, + ) + qr.add_data(rec.display_name) + qr.make(fit=True) + img = qr.make_image(fill_color="black", back_color="white") + + buffer = BytesIO() + img.save(buffer, format="PNG") + qr_code_img = base64.b64encode(buffer.getvalue()).decode() + + rec.qr_code_variant = qr_code_img def _get_clean_website_description(self): for rec in self: diff --git a/indoteknik_custom/models/stock_move.py b/indoteknik_custom/models/stock_move.py index ac2e3cc0..8214a057 100644 --- a/indoteknik_custom/models/stock_move.py +++ b/indoteknik_custom/models/stock_move.py @@ -7,6 +7,18 @@ class StockMove(models.Model): line_no = fields.Integer('No', default=0) sale_id = fields.Many2one('sale.order', string='SO') + print_barcode = fields.Boolean( + string="Print Barcode", + default=lambda self: self.product_id.print_barcode, + ) + + def write(self, vals): + res = super(StockMove, self).write(vals) + if 'print_barcode' in vals: + for line in self: + if line.product_id: + line.product_id.print_barcode = vals['print_barcode'] + return res def _do_unreserve(self, product=None, quantity=False): moves_to_unreserve = OrderedSet() diff --git a/indoteknik_custom/views/product_template.xml b/indoteknik_custom/views/product_template.xml index b6599137..93ea11a2 100755 --- a/indoteknik_custom/views/product_template.xml +++ b/indoteknik_custom/views/product_template.xml @@ -20,6 +20,7 @@ + 0 @@ -29,6 +30,10 @@