summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorit-fixcomart <it@fixcomart.co.id>2024-12-13 15:55:13 +0700
committerit-fixcomart <it@fixcomart.co.id>2024-12-13 15:55:13 +0700
commita9727da77122abc067ab7ff59100fc28eda50642 (patch)
treeb9c0500739518211f1c54ad7f02047872f834afc
parent5343cbd0bfceb6bd50dbbed55a1de4b116f5fef4 (diff)
parent335d724a7f359223138de74bf682cfc3530b5ea7 (diff)
Merge branch 'production' into iman/pengajuan-tempo
-rwxr-xr-xindoteknik_custom/models/product_template.py43
-rw-r--r--indoteknik_custom/models/stock_move.py12
-rw-r--r--indoteknik_custom/models/wati.py63
-rwxr-xr-xindoteknik_custom/views/product_template.xml6
-rw-r--r--indoteknik_custom/views/stock_picking.xml1
5 files changed, 109 insertions, 16 deletions
diff --git a/indoteknik_custom/models/product_template.py b/indoteknik_custom/models/product_template.py
index 6fb8c7a0..00e756c9 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/models/wati.py b/indoteknik_custom/models/wati.py
index f3632334..a0619f83 100644
--- a/indoteknik_custom/models/wati.py
+++ b/indoteknik_custom/models/wati.py
@@ -32,28 +32,43 @@ class WatiNotification(models.Model):
]).unlink()
_logger.info('Success Cleanup WATI Notification')
- def _parse_notification(self, limit = 0):
+ def _parse_notification(self, limit=0):
domain = [('is_parsed', '=', False)]
notifications = self.search(domain, order='id', limit=limit)
notification_not_parsed_count = self.search_count(domain)
i = 0
for notification in notifications:
i += 1
- _logger.info('[Parse Notification][%s] Process: %s/%s | Not Parsed: %s' % (notification.id, i, str(limit), str(notification_not_parsed_count)))
+ _logger.info('[Parse Notification][%s] Process: %s/%s | Not Parsed: %s' %
+ (notification.id, i, str(limit), str(notification_not_parsed_count)))
+
notification_json = json.loads(notification.json_raw)
sender_name = 'Indoteknik'
if 'senderName' in notification_json:
sender_name = notification_json['senderName']
- ticket_id = notification_json['ticketId']
- date_wati = float(notification_json['timestamp'])
- date_wati = datetime.fromtimestamp(date_wati)
+ ticket_id = notification_json.get('ticketId')
+ timestamp = notification_json.get('timestamp')
+
+ if not timestamp:
+ _logger.warning('[Parse Notification][%s] Missing timestamp in notification JSON: %s' %
+ (notification.id, notification.json_raw))
+ continue # Skip this notification
+
+ try:
+ date_wati = datetime.fromtimestamp(float(timestamp))
+ except ValueError as e:
+ _logger.error('[Parse Notification][%s] Invalid timestamp format: %s. Error: %s' %
+ (notification.id, timestamp, str(e)))
+ continue
+
wati_history = self.env['wati.history'].search([('ticket_id', '=', ticket_id)], limit=1)
if wati_history:
self._create_wati_history_line(wati_history, ticket_id, sender_name, notification_json, date_wati)
else:
new_header = self._create_wati_history_header(ticket_id, sender_name, notification_json, date_wati)
self._create_wati_history_line(new_header, ticket_id, sender_name, notification_json, date_wati)
+
notification.is_parsed = True
return
@@ -217,26 +232,42 @@ class WatiHistory(models.Model):
limit = 50
wati_histories = self.env['wati.history'].search(domain, limit=limit)
count = 0
+
for wati_history in wati_histories:
count += 1
- _logger.info('[Parse Notification] Process: %s/%s' % (str(count), str(limit)))
+ _logger.info('[Parse Notification] Processing: %s/%s', count, limit)
wati_api = self.env['wati.api']
- # Perbaikan pada params 'attribute' untuk menghindari masalah "type object is not subscriptable"
+ # Perbaikan pada parameter JSON
params = {
'pageSize': 1,
'pageNumber': 1,
- 'attribute': json.dumps([{'name': "phone", 'operator': "contain", 'value': wati_history.wa_id}]),
+ 'attribute': json.dumps([
+ {'name': "phone", 'operator': "contain", 'value': wati_history.wa_id}
+ ]),
}
- wati_contacts = wati_api.http_get('/api/v1/getContacts', params)
+ try:
+ wati_contacts = wati_api.http_get('/api/v1/getContacts', params)
+ except Exception as e:
+ _logger.error('Error while calling WATI API: %s', str(e))
+ continue
+ # Validasi respons dari API
+ if not isinstance(wati_contacts, dict):
+ _logger.error('Invalid response format from WATI API: %s', wati_contacts)
+ continue
+
if wati_contacts.get('result') != 'success':
- return
+ _logger.warning('WATI API request failed with result: %s', wati_contacts.get('result'))
+ continue
contact_list = wati_contacts.get('contact_list', [])
-
+ if not contact_list:
+ _logger.info('No contacts found for WA ID: %s', wati_history.wa_id)
+ continue
+
perusahaan = email = ''
for data in contact_list:
custom_params = data.get('customParams', [])
@@ -247,12 +278,14 @@ class WatiHistory(models.Model):
perusahaan = value
elif name == 'email':
email = value
- # End inner loop
# Update wati_history fields
- wati_history.perusahaan = perusahaan
- wati_history.email = email
- wati_history.is_get_attribute = True
+ wati_history.write({
+ 'perusahaan': perusahaan,
+ 'email': email,
+ 'is_get_attribute': True,
+ })
+ _logger.info('Wati history updated: %s', wati_history.id)
# @api.onchange('last_reply_date')
# def _compute_expired_date(self):
diff --git a/indoteknik_custom/views/product_template.xml b/indoteknik_custom/views/product_template.xml
index b6599137..af21984a 100755
--- a/indoteknik_custom/views/product_template.xml
+++ b/indoteknik_custom/views/product_template.xml
@@ -20,6 +20,7 @@
<field name="unpublished" />
<field name="desc_update_solr" readonly="1" />
<field name="last_update_solr" readonly="1" />
+ <!-- <field name="qr_code" widget="image" invisible="1"/> -->
</field>
<field name="public_categ_ids" position="attributes">
<attribute name="required">0</attribute>
@@ -29,6 +30,10 @@
<field name="merchandise_ok"/>
<label for="merchandise_ok"/>
</div>
+ <div>
+ <field name="print_barcode"/>
+ <label for="print_barcode"/>
+ </div>
</div>
<field name="public_categ_ids" position="attributes">
<attribute name="options">{'no_create': True}</attribute>
@@ -58,6 +63,7 @@
<field name="arch" type="xml">
<field name="last_update_solr" position="after">
<field name="clean_website_description" />
+ <field name="qr_code_variant" widget="image" readonly="True"/>
</field>
</field>
</record>
diff --git a/indoteknik_custom/views/stock_picking.xml b/indoteknik_custom/views/stock_picking.xml
index 57291316..8a3ea1cb 100644
--- a/indoteknik_custom/views/stock_picking.xml
+++ b/indoteknik_custom/views/stock_picking.xml
@@ -122,6 +122,7 @@
</field>
<field name="product_uom" position="after">
<field name="sale_id" attrs="{'readonly': 1}" optional="hide"/>
+ <field name="print_barcode" optional="hide"/>
</field>
<page name="note" position="after">
<page string="E-Faktur" name="efaktur" attrs="{'invisible': [['is_internal_use', '=', False]]}">