summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMiqdad <ahmadmiqdad27@gmail.com>2025-11-11 13:35:02 +0700
committerMiqdad <ahmadmiqdad27@gmail.com>2025-11-11 13:35:02 +0700
commit4c69c892f7b8ef7ec0877023f3f9544c8e9eb42c (patch)
tree038e771e90339517d64a933175d87cc48c3c7f72
parent062c606f4c31ee0966a6c08f4f3de52d719df883 (diff)
parent0373d7545ec889d8cdfee6d09bb93123df5a60cb (diff)
<Miqdad> merge
-rw-r--r--indoteknik_custom/models/advance_payment_request.py4
-rw-r--r--indoteknik_custom/models/automatic_purchase.py3
-rw-r--r--indoteknik_custom/models/commision.py4
-rw-r--r--indoteknik_custom/models/coretax_fatur.py4
-rwxr-xr-xindoteknik_custom/models/sale_order.py52
-rw-r--r--indoteknik_custom/models/stock_move.py26
-rw-r--r--indoteknik_custom/models/stock_picking.py60
-rw-r--r--indoteknik_custom/report/purchase_report.xml2
-rwxr-xr-xindoteknik_custom/views/sale_order.xml1
-rw-r--r--indoteknik_custom/views/stock_picking.xml14
10 files changed, 136 insertions, 34 deletions
diff --git a/indoteknik_custom/models/advance_payment_request.py b/indoteknik_custom/models/advance_payment_request.py
index a3a3d20a..6ea1c160 100644
--- a/indoteknik_custom/models/advance_payment_request.py
+++ b/indoteknik_custom/models/advance_payment_request.py
@@ -846,9 +846,9 @@ class AdvancePaymentUsageLine(models.Model):
attachment_filename_pdf = fields.Char(string='Filename PDF')
account_id = fields.Many2one(
- 'account.account', string='Jenis Biaya', tracking=3,
- domain="[('id', 'in', [484, 486, 488, 506, 507, 625, 471, 519, 527, 528, 529, 530, 565])]" # ID Jenis Biaya yang dibutuhkan
+ 'account.account', string='Jenis Biaya', tracking=3 # ID Jenis Biaya yang dibutuhkan
)
+ # domain="[('id', 'in', [484, 486, 488, 506, 507, 625, 471, 519, 527, 528, 529, 530, 565])]" # ID Jenis Biaya yang dibutuhkan
is_current_user_ap = fields.Boolean(
string="Is Current User AP",
diff --git a/indoteknik_custom/models/automatic_purchase.py b/indoteknik_custom/models/automatic_purchase.py
index ce0328c4..4b0ce325 100644
--- a/indoteknik_custom/models/automatic_purchase.py
+++ b/indoteknik_custom/models/automatic_purchase.py
@@ -284,7 +284,8 @@ class AutomaticPurchase(models.Model):
'ending_price': line.last_price,
'taxes_id': [(6, 0, [line.taxes_id.id])] if line.taxes_id else False,
'so_line_id': sales_match.sale_line_id.id if sales_match else None,
- 'so_id': sales_match.sale_id.id if sales_match else None
+ 'so_id': sales_match.sale_id.id if sales_match else None,
+ 'show_description': False if vendor_id == 5571 else True,
}
new_po_line = self.env['purchase.order.line'].create(param_line)
line.current_po_id = new_po.id
diff --git a/indoteknik_custom/models/commision.py b/indoteknik_custom/models/commision.py
index a937e2d0..441dd54f 100644
--- a/indoteknik_custom/models/commision.py
+++ b/indoteknik_custom/models/commision.py
@@ -423,8 +423,8 @@ class CustomerCommision(models.Model):
def action_confirm_customer_commision(self):
jakarta_tz = pytz.timezone('Asia/Jakarta')
now = datetime.now(jakarta_tz)
-
- now_naive = now.replace(tzinfo=None)
+ now_utc = now.astimezone(pytz.utc)
+ now_naive = now_utc.replace(tzinfo=None)
if not self.status or self.status == 'draft':
self.status = 'pengajuan1'
diff --git a/indoteknik_custom/models/coretax_fatur.py b/indoteknik_custom/models/coretax_fatur.py
index ce94306f..7e0de919 100644
--- a/indoteknik_custom/models/coretax_fatur.py
+++ b/indoteknik_custom/models/coretax_fatur.py
@@ -147,6 +147,8 @@ class CoretaxFaktur(models.Model):
subtotal = line_price_subtotal
quantity = line_quantity
total_discount = round(line_discount, 2)
+ coretax_id = line.product_uom_id.coretax_id
+ uom_name = line.product_uom_id.name
# Calculate other tax values
otherTaxBase = round(subtotal * (11 / 12), 2) if subtotal else 0
@@ -159,7 +161,7 @@ class CoretaxFaktur(models.Model):
ET.SubElement(good_service, 'Opt').text = 'A'
ET.SubElement(good_service, 'Code').text = '000000'
ET.SubElement(good_service, 'Name').text = line_name
- ET.SubElement(good_service, 'Unit').text = 'UM.0018'
+ ET.SubElement(good_service, uom_name).text = coretax_id
# ET.SubElement(good_service, 'Price').text = str(round(line_price_unit, 2)) if line_price_unit else '0'
ET.SubElement(good_service, 'Price').text = str(price_per_unit)
ET.SubElement(good_service, 'Qty').text = str(quantity)
diff --git a/indoteknik_custom/models/sale_order.py b/indoteknik_custom/models/sale_order.py
index 1d07a1ff..357d2395 100755
--- a/indoteknik_custom/models/sale_order.py
+++ b/indoteknik_custom/models/sale_order.py
@@ -398,6 +398,45 @@ class SaleOrder(models.Model):
compute="_compute_partner_is_cbd_locked"
)
internal_notes_contact = fields.Text(related='partner_id.comment', string="Internal Notes", readonly=True, help="Internal Notes dari contact utama customer.")
+ is_so_fiktif = fields.Boolean('SO Fiktif?')
+
+ def action_set_shipping_id(self):
+ for rec in self:
+ bu_pick = self.env['stock.picking'].search([
+ ('state', 'not in', ['cancel']),
+ ('picking_type_id', '=', 30),
+ ('sale_id', '=', rec.id),
+ ('linked_manual_bu_out', '=', False)
+ ])
+ # bu_out = bu_pick_has_out.mapped('linked_manual_bu_out')
+ bu_out = self.env['stock.picking'].search([
+ ('sale_id', '=', rec.id),
+ ('picking_type_id', '=', 29),
+ ('state', 'not in', ['cancel', 'done'])
+ ])
+ bu_pick_has_out = self.env['stock.picking'].search([
+ ('state', 'not in', ['cancel']),
+ ('picking_type_id', '=', 30),
+ ('sale_id', '=', rec.id),
+ ('linked_manual_bu_out.id', '=', bu_out.id),
+ ('linked_manual_bu_out.state', 'not in', ['done', 'cancel'])
+ ])
+ for pick in bu_pick_has_out:
+ linked_out = pick.linked_manual_bu_out
+ if pick.real_shipping_id != rec.real_shipping_id or linked_out.partner_id != rec.partner_shipping_id:
+ pick.real_shipping_id = rec.real_shipping_id
+ pick.partner_id = rec.partner_shipping_id
+ linked_out.partner_id = rec.partner_shipping_id
+ linked_out.real_shipping_id = rec.real_shipping_id
+ _logger.info('Updated bu_pick [%s] and bu_out [%s]', pick.name, linked_out.name)
+
+ for pick in bu_pick:
+ if pick.real_shipping_id != rec.real_shipping_id:
+ pick.real_shipping_id = rec.real_shipping_id
+ pick.partner_id = rec.partner_shipping_id
+ bu_out.partner_id = rec.partner_shipping_id
+ bu_out.real_shipping_id = rec.real_shipping_id
+ _logger.info('Updated bu_pick [%s] without bu_out', pick.name)
def action_open_partial_delivery_wizard(self):
# raise UserError("Fitur ini sedang dalam pengembangan")
@@ -2278,7 +2317,7 @@ class SaleOrder(models.Model):
raise UserError("Terdapat DUPLIKASI data pada Product {}".format(line.product_id.display_name))
def sale_order_approve(self):
- # self.check_duplicate_product()
+ self.check_duplicate_product()
self.check_product_bom()
self.check_credit_limit()
self.check_limit_so_to_invoice()
@@ -2356,6 +2395,7 @@ class SaleOrder(models.Model):
self.check_credit_limit()
self.check_limit_so_to_invoice()
order.approval_status = 'pengajuan1'
+ order.message_post(body="Mengajukan approval ke Team Sales")
return self._create_approval_notification('Team Sales')
if not order.with_context(ask_approval=True)._is_request_to_own_team_leader():
@@ -2549,7 +2589,7 @@ class SaleOrder(models.Model):
for order in self:
order._validate_delivery_amt()
order._validate_uniform_taxes()
- # order.check_duplicate_product()
+ order.check_duplicate_product()
order.check_product_bom()
order.check_credit_limit()
order.check_limit_so_to_invoice()
@@ -2598,6 +2638,7 @@ class SaleOrder(models.Model):
return self._create_approval_notification('Sales Manager')
elif order._requires_approval_team_sales():
order.approval_status = 'pengajuan1'
+ order.message_post(body="Mengajukan approval ke Team Sales")
return self._create_approval_notification('Team Sales')
order.approval_status = 'approved'
@@ -2703,8 +2744,8 @@ class SaleOrder(models.Model):
def _requires_approval_team_sales(self):
return (
- # 18 <= self.total_percent_margin <= 24
- self.total_percent_margin >= 18
+ 18 <= self.total_percent_margin <= 24
+ # self.total_percent_margin >= 18
and self.env.user.id not in [11, 9, 375] # Eko, Ade, Putra
and not self.env.user.is_sales_manager
and not self.env.user.is_leader
@@ -3376,6 +3417,9 @@ class SaleOrder(models.Model):
# if updated_vals:
# line.write(updated_vals)
+
+ if 'real_shipping_id' in vals:
+ self.action_set_shipping_id()
return res
def button_refund(self):
diff --git a/indoteknik_custom/models/stock_move.py b/indoteknik_custom/models/stock_move.py
index 38cf0199..cac88287 100644
--- a/indoteknik_custom/models/stock_move.py
+++ b/indoteknik_custom/models/stock_move.py
@@ -22,12 +22,12 @@ class StockMove(models.Model):
partial = fields.Boolean('Partial?', default=False)
# Ambil product uom dari SO line
- # @api.model
- # def create(self, vals):
- # if vals.get('sale_line_id'):
- # sale_line = self.env['sale.order.line'].browse(vals['sale_line_id'])
- # vals['product_uom'] = sale_line.product_uom.id
- # return super().create(vals)
+ @api.model
+ def create(self, vals):
+ if vals.get('sale_line_id'):
+ sale_line = self.env['sale.order.line'].browse(vals['sale_line_id'])
+ vals['product_uom'] = sale_line.product_uom.id
+ return super().create(vals)
# @api.model_create_multi
# def create(self, vals_list):
@@ -282,10 +282,10 @@ class StockMoveLine(models.Model):
picking.delivery_status = 'none'
# Ambil uom dari stock move
- # @api.model
- # def create(self, vals):
- # if 'move_id' in vals and 'product_uom_id' not in vals:
- # move = self.env['stock.move'].browse(vals['move_id'])
- # if move.product_uom:
- # vals['product_uom_id'] = move.product_uom.id
- # return super().create(vals) \ No newline at end of file
+ @api.model
+ def create(self, vals):
+ if 'move_id' in vals and 'product_uom_id' not in vals:
+ move = self.env['stock.move'].browse(vals['move_id'])
+ if move.product_uom:
+ vals['product_uom_id'] = move.product_uom.id
+ return super().create(vals) \ No newline at end of file
diff --git a/indoteknik_custom/models/stock_picking.py b/indoteknik_custom/models/stock_picking.py
index 04847be8..49001974 100644
--- a/indoteknik_custom/models/stock_picking.py
+++ b/indoteknik_custom/models/stock_picking.py
@@ -5,16 +5,16 @@ from collections import defaultdict
from datetime import timedelta, datetime
from datetime import timedelta, datetime as waktu
from itertools import groupby
-import pytz, requests, json, requests
+import pytz, json
from dateutil import parser
import datetime
import hmac
import hashlib
-import base64
import requests
import time
import logging
import re
+import base64
_logger = logging.getLogger(__name__)
@@ -200,6 +200,13 @@ class StockPicking(models.Model):
('full', 'Full'),
], string='Delivery Status', compute='_compute_delivery_status_detail', store=False)
so_num = fields.Char('SO Number', compute='_get_so_num')
+ is_so_fiktif = fields.Boolean('SO Fiktif?', compute='_compute_is_so_fiktif')
+
+ @api.depends('sale_id.is_so_fiktif')
+ def _compute_is_so_fiktif(self):
+ for picking in self:
+ picking.is_so_fiktif = picking.sale_id.is_so_fiktif if picking.sale_id else False
+
@api.depends('group_id')
def _get_so_num(self):
@@ -816,6 +823,37 @@ class StockPicking(models.Model):
picking.envio_cod_value = data.get("cod_value", 0.0)
picking.envio_cod_status = data.get("cod_status")
+ images_data = data.get('images', [])
+ for img in images_data:
+ image_url = img.get('image')
+ if image_url:
+ try:
+ # Download image from URL
+ img_response = requests.get(image_url)
+ img_response.raise_for_status()
+
+ # Encode image to base64
+ image_base64 = base64.b64encode(img_response.content)
+
+ # Create attachment in Odoo
+ attachment = self.env['ir.attachment'].create({
+ 'name': 'Envio Image',
+ 'type': 'binary',
+ 'datas': image_base64,
+ 'res_model': picking._name,
+ 'res_id': picking.id,
+ 'mimetype': 'image/png',
+ })
+
+ # Post log note with attachment
+ picking.message_post(
+ body="Image Envio",
+ attachment_ids=[attachment.id]
+ )
+
+ except Exception as e:
+ picking.message_post(body=f"Gagal ambil image Envio: {str(e)}")
+
# Menyimpan log terbaru
logs = data.get("logs", [])
if logs and isinstance(logs, list) and logs[0]:
@@ -1378,6 +1416,8 @@ class StockPicking(models.Model):
group_id = self.env.ref('indoteknik_custom.group_role_merchandiser').id
users_in_group = self.env['res.users'].search([('groups_id', 'in', [group_id])])
active_model = self.env.context.get('active_model')
+ if self.is_so_fiktif == True:
+ raise UserError("SO Fiktif tidak bisa di validate")
if self.location_id.id == 47 and self.env.user.id not in users_in_group.mapped(
'id') and self.state_approve_md != 'done':
self.state_approve_md = 'waiting' if self.state_approve_md != 'pending' else 'pending'
@@ -1416,6 +1456,9 @@ class StockPicking(models.Model):
if len(self.check_product_lines) == 0 and 'BU/PICK/' in self.name:
raise UserError(_("Tidak ada Check Product! Harap periksa kembali."))
+ if len(self.check_product_lines) == 0 and 'BU/INPUT/' in self.name:
+ raise UserError(_("Tidak ada Check Product! Harap periksa kembali."))
+
if self.total_koli > self.total_so_koli:
raise UserError(_("Total Koli (%s) dan Total SO Koli (%s) tidak sama! Harap periksa kembali.")
% (self.total_koli, self.t1otal_so_koli))
@@ -1559,6 +1602,10 @@ class StockPicking(models.Model):
elif self.tukar_guling_po_id:
self.tukar_guling_po_id.update_doc_state()
+ user = self.env.user
+ if not user.has_group('indoteknik_custom.group_role_logistic'):
+ raise UserWarning('Validate hnaya bisa di lakukan oleh logistik')
+
return res
def automatic_reserve_product(self):
@@ -1729,6 +1776,15 @@ class StockPicking(models.Model):
'indoteknik_custom.group_role_logistic') and self.picking_type_code == 'outgoing':
raise UserError("Button ini hanya untuk Logistik")
+ if len(self.check_product_lines) >= 1:
+ raise UserError("Tidak Bisa cancel karena sudah di check product")
+
+ if not self.env.user.is_logistic_approver and not self.env.user.has_group('indoteknik_custom.group_role_logistic'):
+ for picking in self:
+ if picking.name and ('BU/PICK' in picking.name or 'BU/OUT' in picking.name or 'BU/ORT' in picking.name or 'BU/SRT' in picking.name):
+ if picking.state not in ['cancel']:
+ raise UserError("Button ini hanya untuk Logistik")
+
res = super(StockPicking, self).action_cancel()
return res
diff --git a/indoteknik_custom/report/purchase_report.xml b/indoteknik_custom/report/purchase_report.xml
index 9c0c3983..208e6472 100644
--- a/indoteknik_custom/report/purchase_report.xml
+++ b/indoteknik_custom/report/purchase_report.xml
@@ -131,7 +131,7 @@
</tr>
<!-- WEBSITE DESCRIPTION -->
- <t t-if="line.show_description">
+ <t t-if="line.show_description == True">
<tr t-attf-style="background-color: #{ '#fef5f5' if line_index % 2 == 0 else '#fffafa' }; ">
<td colspan="6" style="padding: 10px 14px; font-size:10px; line-height:1.3; font-style:italic; color:#555; border-left:1px solid #ccc; border-right:1px solid #ccc; border-bottom:1px solid #ccc;">
<div t-raw="line.product_id.website_description"/>
diff --git a/indoteknik_custom/views/sale_order.xml b/indoteknik_custom/views/sale_order.xml
index a540caa7..b2ecc21c 100755
--- a/indoteknik_custom/views/sale_order.xml
+++ b/indoteknik_custom/views/sale_order.xml
@@ -130,6 +130,7 @@
</field>
<field name="approval_status" position="after">
<field name="notes"/>
+ <field name="is_so_fiktif"/>
</field>
<field name="source_id" position="attributes">
<attribute name="invisible">1</attribute>
diff --git a/indoteknik_custom/views/stock_picking.xml b/indoteknik_custom/views/stock_picking.xml
index 2925cf2c..4779c5d3 100644
--- a/indoteknik_custom/views/stock_picking.xml
+++ b/indoteknik_custom/views/stock_picking.xml
@@ -147,7 +147,7 @@
<attribute name="attrs">{'readonly': [('parent.picking_type_code', '=', 'incoming')]}</attribute>
</field> -->
<field name="date_done" position="after">
- <field name="arrival_time"/>
+ <field name="arrival_time" attrs="{'invisible': [('picking_type_id', 'in', [29,30])]}"/>
</field>
<field name="scheduled_date" position="attributes">
<attribute name="readonly">1</attribute>
@@ -162,11 +162,12 @@
<field name="origin" position="after">
<!-- <field name="show_state_approve_md" invisible="1" optional="hide"/>-->
- <field name="state_approve_md" widget="badge"/>
+ <field name="state_approve_md" widget="badge" attrs="{'invisible': [('picking_type_id', 'in', [29,30])]}"/>
<field name="purchase_id"/>
<field name="sale_order"/>
<field name="invoice_status"/>
- <field name="is_bu_iu"/>
+ <field name="is_bu_iu" />
+ <field name="is_so_fiktif" readonly="1"/>
<field name="approval_status" attrs="{'invisible': [('is_bu_iu', '=', False)]}"/>
<field name="date_doc_kirim" attrs="{'readonly':[('invoice_status', '=', 'invoiced')]}"/>
<field name="summary_qty_operation"/>
@@ -412,8 +413,7 @@
<field name="qty_yang_mau_dikirim"/>
<field name="qty_terkirim"/>
<field name="qty_gantung"/>
- <field name="delivery_status" widget="badge"
- options="{'colors': {'full': 'success', 'partial': 'warning', 'partial_final': 'danger'}}"/>
+ <field name="delivery_status" widget="badge" options="{'colors': {'full': 'success', 'partial': 'warning', 'partial_final': 'danger'}}"/>
</tree>
</field>
</record>
@@ -437,9 +437,7 @@
<form string="Peringatan Koli Belum Diperiksa">
<sheet>
<div class="oe_title">
- <h2>
- <span>⚠️ Perhatian!</span>
- </h2>
+ <h2><span>⚠️ Perhatian!</span></h2>
</div>
<group>
<field name="message" readonly="1" nolabel="1" widget="text"/>