summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorit-fixcomart <it@fixcomart.co.id>2024-12-09 15:05:00 +0700
committerit-fixcomart <it@fixcomart.co.id>2024-12-09 15:05:00 +0700
commit31374ed669121ba6c8ec401f82ad0bfedf07a6d6 (patch)
tree0aa9bf91134ad7fe07142c37873ddeed3b6f3c71
parent02eacd54387953f42a884a22544e2f7c94081536 (diff)
parent2123dbaab7b4ff49d90336d34e2be76e8eb07f8e (diff)
Merge branch 'production' into iman/pengajuan-tempo
-rw-r--r--indoteknik_api/controllers/controller.py30
-rw-r--r--indoteknik_api/models/res_users.py2
-rwxr-xr-xindoteknik_custom/models/product_template.py4
-rw-r--r--indoteknik_custom/models/stock_picking.py122
-rw-r--r--indoteknik_custom/models/stock_picking_return.py14
-rw-r--r--indoteknik_custom/views/stock_picking.xml23
6 files changed, 182 insertions, 13 deletions
diff --git a/indoteknik_api/controllers/controller.py b/indoteknik_api/controllers/controller.py
index a34a2688..80f45074 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.format == "PNG" and image.mode != "RGBA":
+ image = image.convert("RGBA")
+
+ # 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 ''
diff --git a/indoteknik_api/models/res_users.py b/indoteknik_api/models/res_users.py
index 93204a96..d9329f67 100644
--- a/indoteknik_api/models/res_users.py
+++ b/indoteknik_api/models/res_users.py
@@ -79,7 +79,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'] = {
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')
diff --git a/indoteknik_custom/models/stock_picking.py b/indoteknik_custom/models/stock_picking.py
index 03b10cdb..e6506a0b 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 timedelta, datetime
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,120 @@ 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.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.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)
+
+ 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.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
+ date = datetime.datetime.strptime(date_str, '%Y-%m-%dT%H:%M:%S.%fZ')
+ return date
+ except ValueError:
+ try:
+ # Format waktu tanpa milidetik
+ 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}")
+
+ 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")
+ envio_ata = self._convert_to_datetime(data.get("ata_at"))
+
+ 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: {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 +655,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':
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
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"
/>
+ <button name="track_envio_shipment"
+ string="Tracking Envio"
+ type="object"
+ attrs="{'invisible': [('carrier_id', '!=', 151)]}"
+ />
</button>
<field name="backorder_id" position="after">
<field name="summary_qty_detail"/>
@@ -143,6 +148,24 @@
<field name="sj_documentation" widget="image" />
<field name="paket_documentation" widget="image" />
</group>
+ <group>
+ <field name="envio_id" invisible="1"/>
+ <field name="envio_code"/>
+ <field name="envio_ref_code"/>
+ <field name="envio_eta_at"/>
+ <field name="envio_ata_at"/>
+ <field name="envio_etd_at" invisible="1"/>
+ <field name="envio_atd_at" invisible="1"/>
+ <field name="envio_received_by"/>
+ <field name="envio_status"/>
+ <field name="envio_cod_value" invisible="1"/>
+ <field name="envio_cod_status" invisible="1"/>
+ <field name="envio_latest_message"/>
+ <field name="envio_latest_recorded_at"/>
+ <field name="envio_latest_latitude" invisible="1"/>
+ <field name="envio_latest_longitude" invisible="1"/>
+ <field name="tracking_by" invisible="1"/>
+ </group>
</group>
</page>
</page>