summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorstephanchrst <stephanchrst@gmail.com>2024-11-11 14:11:42 +0700
committerstephanchrst <stephanchrst@gmail.com>2024-11-11 14:11:42 +0700
commitfd6b9b5395b04135d9f0afdc0859fb4f07d280b4 (patch)
treebe6e7a4f201b949a3b06e0c020c668ba2b0730fa
parentf787f06a341f1775151d98be4490fe6126c511cd (diff)
parent9a0fd25e54491bd14a5b29b62b31a440dfa1bebc (diff)
Merge branch 'production' into feature/max_plafon_order_qty
-rw-r--r--indoteknik_api/controllers/api_v1/stock_picking.py2
-rw-r--r--indoteknik_custom/models/approval_date_doc.py1
-rw-r--r--indoteknik_custom/models/delivery_order.py4
-rwxr-xr-xindoteknik_custom/models/product_template.py49
-rwxr-xr-xindoteknik_custom/models/purchase_order.py12
-rw-r--r--indoteknik_custom/models/requisition.py55
-rwxr-xr-xindoteknik_custom/models/sale_order.py2
-rw-r--r--indoteknik_custom/models/sale_order_line.py11
-rw-r--r--indoteknik_custom/models/stock_picking.py33
-rw-r--r--indoteknik_custom/models/website_user_cart.py41
-rw-r--r--indoteknik_custom/views/requisition.xml7
11 files changed, 146 insertions, 71 deletions
diff --git a/indoteknik_api/controllers/api_v1/stock_picking.py b/indoteknik_api/controllers/api_v1/stock_picking.py
index f0c7456d..ea8c6400 100644
--- a/indoteknik_api/controllers/api_v1/stock_picking.py
+++ b/indoteknik_api/controllers/api_v1/stock_picking.py
@@ -123,7 +123,7 @@ class StockPicking(controller.Controller):
params = {'sj_documentation': sj_document,
'paket_documentation': paket_document,
- 'driver_arrival_date': self.time_to_str(datetime.utcnow(), '%Y-%m-%d %H:%M:%S'),
+ 'driver_arrival_date': datetime.utcnow(),
}
picking_data = request.env['stock.picking'].search([('picking_code', '=', picking_code)], limit=1)
diff --git a/indoteknik_custom/models/approval_date_doc.py b/indoteknik_custom/models/approval_date_doc.py
index 441ada3d..751bae82 100644
--- a/indoteknik_custom/models/approval_date_doc.py
+++ b/indoteknik_custom/models/approval_date_doc.py
@@ -40,6 +40,7 @@ class ApprovalDateDoc(models.Model):
raise UserError("Hanya Accounting Yang Bisa Approve")
self.check_invoice_so_picking
self.picking_id.driver_departure_date = self.driver_departure_date
+ self.picking_id.date_doc_kirim = self.driver_departure_date
self.state = 'done'
self.approve_date = datetime.utcnow()
self.approve_by = self.env.user.id
diff --git a/indoteknik_custom/models/delivery_order.py b/indoteknik_custom/models/delivery_order.py
index 2ed49a54..3473197b 100644
--- a/indoteknik_custom/models/delivery_order.py
+++ b/indoteknik_custom/models/delivery_order.py
@@ -33,11 +33,13 @@ class DeliveryOrder(models.TransientModel):
picking.driver_id = self.env.uid
picking.delivery_tracking_no = line_tracking_no
+ if picking.driver_departure_date:
+ picking.sj_return_date = datetime.utcnow()
+
delivery_type = self.env['delivery.order.line'].get_delivery_type(picking.driver_departure_date, picking.driver_arrival_date)
if delivery_type == 'departure':
picking.driver_departure_date = current_time
elif delivery_type == 'arrival':
- picking.sj_return_date = datetime.utcnow()
sale_order = False
if picking.origin:
diff --git a/indoteknik_custom/models/product_template.py b/indoteknik_custom/models/product_template.py
index d3343e75..3bb06eaf 100755
--- a/indoteknik_custom/models/product_template.py
+++ b/indoteknik_custom/models/product_template.py
@@ -391,23 +391,46 @@ class ProductProduct(models.Model):
@api.constrains('active')
def archive_product(self):
for product in self:
+ if self.env.context.get('skip_unpublished_constraint'):
+ continue # Mencegah looping saat dipanggil dari metode lain
+
product_template = product.product_tmpl_id
variants = product_template.product_variant_ids
- if product_template.active and product.active:
- if not product.active and len(variants) == 1:
- product_template.with_context(skip_active_constraint=True).active = False
- product_template.unpublished = True
- elif not product.active and len(variants) > 1:
+ if len(variants) == 1:
+ # Jika hanya ada satu varian, atur status `unpublished` berdasarkan `active`
+ product_template.with_context(skip_unpublished_constraint=True).unpublished = not product.active
+ product.with_context(skip_unpublished_constraint=True).unpublished = not product.active
+ else:
+ if product.active:
+ product.with_context(skip_unpublished_constraint=True).unpublished = False
+ product_template.with_context(skip_unpublished_constraint=True).unpublished = any(variant.active for variant in variants)
+ else:
+ product.with_context(skip_unpublished_constraint=True).unpublished = True
all_inactive = all(not variant.active for variant in variants)
- if all_inactive:
- product_template.with_context(skip_active_constraint=True).active = False
- product_template.unpublished = True
- else:
- continue
- if any(variant.active for variant in variants):
- product_template.unpublished = False
- variants.unpublished = False
+ product_template.with_context(skip_unpublished_constraint=True).unpublished = all_inactive
+
+ @api.constrains('unpublished')
+ def archive_product_unpublished(self):
+ for product in self:
+ if self.env.context.get('skip_active_constraint'):
+ continue # Mencegah looping saat dipanggil dari metode lain
+
+ product_template = product.product_tmpl_id
+ variants = product_template.product_variant_ids
+
+ if len(variants) == 1:
+ # Jika hanya ada satu varian, atur status `unpublished` pada template, tetapi biarkan `active` tetap True
+ product_template.with_context(skip_active_constraint=True).unpublished = product.unpublished
+ else:
+ if not product.unpublished:
+ # Jika `unpublished` adalah False, pastikan `active` tetap True
+ product.with_context(skip_active_constraint=True).active = True
+ product_template.with_context(skip_active_constraint=True).active = any(not variant.unpublished for variant in variants)
+ else:
+ # Jika `unpublished` adalah True, atur template hanya jika semua varian di-unpublished
+ all_unpublished = all(variant.unpublished for variant in variants)
+ product_template.with_context(skip_active_constraint=True).active = not all_unpublished
def update_internal_reference_variants(self, limit=100):
variants = self.env['product.product'].search([
diff --git a/indoteknik_custom/models/purchase_order.py b/indoteknik_custom/models/purchase_order.py
index 231acb4c..f5b5979b 100755
--- a/indoteknik_custom/models/purchase_order.py
+++ b/indoteknik_custom/models/purchase_order.py
@@ -605,7 +605,7 @@ class PurchaseOrder(models.Model):
if self.total_percent_margin < self.total_so_percent_margin and not self.env.user.has_group('indoteknik_custom.group_role_merchandiser') and not self.env.user.is_leader:
raise UserError("Beda Margin dengan Sales, harus approval Merchandise")
if not self.from_apo:
- if not self.sale_order_id and not self.env.user.has_group('indoteknik_custom.group_role_merchandiser') and not self.env.user.is_leader:
+ if not self.matches_so and not self.env.user.has_group('indoteknik_custom.group_role_merchandiser') and not self.env.user.is_leader:
raise UserError("Tidak ada link dengan SO, harus approval Merchandise")
send_email = False
@@ -738,7 +738,7 @@ class PurchaseOrder(models.Model):
raise UserError("Hanya Merchandiser yang bisa approve")
if self.env.user.is_leader or self.env.user.has_group('indoteknik_custom.group_role_merchandiser'):
raise UserError("Bisa langsung Confirm")
- elif self.total_percent_margin == self.total_so_percent_margin and self.sale_order_id:
+ elif self.total_percent_margin == self.total_so_percent_margin and self.matches_so:
raise UserError("Bisa langsung Confirm")
else:
reason = ''
@@ -747,12 +747,14 @@ class PurchaseOrder(models.Model):
reason = 'above 50jt, '
if self.total_percent_margin < self.total_so_percent_margin:
reason += 'diff margin, '
- if not self.from_apo and not self.sale_order_id:
- reason += 'not link with sales, '
+ if not self.from_apo and not self.matches_so:
+ reason += 'not link with pj and reorder, '
+ if not self.matches_so:
+ reason += 'not link with so, '
# Post a highlighted message to lognote
self.message_post(
body=f"<div style='background-color: #fdf2e9; border: 1px solid #f5c6cb; padding: 10px;'>"
- f"<b>Note Return (Pinned):</b><br>{reason}</div>",
+ f"<b>Note (Pinned):</b><br>{reason}</div>",
subtype_id=self.env.ref("mail.mt_note").id
)
diff --git a/indoteknik_custom/models/requisition.py b/indoteknik_custom/models/requisition.py
index c4104ec5..704ae8c0 100644
--- a/indoteknik_custom/models/requisition.py
+++ b/indoteknik_custom/models/requisition.py
@@ -1,4 +1,4 @@
-from odoo import models, fields, api, _
+from odoo import models, fields, api, tools, _
from odoo.exceptions import UserError
from datetime import datetime
import math
@@ -7,6 +7,33 @@ import logging
_logger = logging.getLogger(__name__)
+class RequisitionMatchPO(models.Model):
+ _name = 'v.requisition.match.po'
+ _auto = False
+ _rec_name = 'purchase_id'
+
+ id = fields.Integer(string='ID')
+ product_id = fields.Many2one('product.product', string='Product')
+ qty_rpo = fields.Float(string='Qty RPO', help='Qty RPO yang sudah di PO namun SO masih Draft')
+
+ def init(self):
+ tools.drop_view_if_exists(self.env.cr, self._table)
+ self.env.cr.execute("""
+ create or replace view %s as
+ select rl.product_id as id, rl.product_id, sum(rl.qty_purchase) as qty_rpo
+ from requisition_line rl
+ join requisition r on r.id = rl.requisition_id
+ join requisition_purchase_match rpm on rpm.requisition_id = r.id
+ join purchase_order po on po.id = rpm.order_id
+ join sale_order so on so.id = r.sale_order_id
+ where 1=1
+ and r.date_doc >= '2024-11-11'
+ and po.state in ('done', 'purchase')
+ and so.state in ('draft', 'sent')
+ group by rl.product_id
+ """ % self._table)
+
+
class Requisition(models.Model):
_name = 'requisition'
_order = 'id desc'
@@ -22,19 +49,36 @@ class Requisition(models.Model):
requisition_match = fields.One2many('requisition.purchase.match', 'requisition_id', string='Matches', auto_join=True)
sale_order_id = fields.Many2one('sale.order', string='SO', help='harus diisi nomor SO yang ingin digenerate',
domain="[('state', '=', 'sale')]")
+ sales_approve = fields.Boolean(string='Sales Approve', tracking=3, copy=False)
+ merchandise_approve = fields.Boolean(string='Merchandise Approve', tracking=3, copy=False)
@api.model
def create(self, vals):
vals['number'] = self.env['ir.sequence'].next_by_code('requisition') or '0'
result = super(Requisition, self).create(vals)
return result
-
+
+ def button_approve(self):
+ if self.env.user.id not in [377, 19]:
+ raise UserError('Hanya Vita dan Darren Yang Bisa Approve')
+ if self.env.user.id == 377:
+ self.sales_approve = True
+ elif self.env.user.id == 19:
+ if not self.sales_approve:
+ raise UserError('Vita Belum Approve')
+ self.merchandise_approve = True
def create_po_from_requisition(self):
+ if not self.sales_approve:
+ raise UserError('Harus di Approve Vita')
+ if not self.merchandise_approve:
+ raise UserError('Harus di Approve Darren')
if not self.requisition_lines:
raise UserError('Tidak ada Lines, belum bisa create PO')
if self.is_po:
raise UserError('Sudah pernah di create PO')
+ if self.sale_order_id:
+ raise UserError('Tidak ada link dengan Sales Order, tidak bisa dihitung sebagai Plafon Qty di PO')
vendor_ids = self.env['requisition.line'].read_group([
('requisition_id', '=', self.id),
@@ -108,6 +152,13 @@ class Requisition(models.Model):
new_po_line = self.env['purchase.order.line'].create([param_line])
line.current_po_id = new_po.id
line.current_po_line_id = new_po_line.id
+
+ self.env['requisition.purchase.match'].create([{
+ 'requisition_id': self.id,
+ 'order_id': new_po.id
+ }])
+ self.is_po = True
+
return po_ids
# def create_po_from_requisition(self):
diff --git a/indoteknik_custom/models/sale_order.py b/indoteknik_custom/models/sale_order.py
index 8e170b1c..5545e28c 100755
--- a/indoteknik_custom/models/sale_order.py
+++ b/indoteknik_custom/models/sale_order.py
@@ -78,7 +78,7 @@ class SaleOrder(models.Model):
payment_link_midtrans = fields.Char(string='Payment Link', help='Url payment yg digenerate oleh midtrans, harap diserahkan ke customer agar dapat dilakukan pembayaran secara mandiri')
payment_qr_code = fields.Binary("Payment QR Code")
due_id = fields.Many2one('due.extension', string="Due Extension", readonly=True, tracking=True)
- vendor_approval_id = fields.Many2one('vendor.approval', string="Vendor Approval", readonly=True, tracking=True)
+ vendor_approval_id = fields.Many2one('vendor.approval', string="Vendor Approval", readonly=True, tracking=True, copy=False)
customer_type = fields.Selection([
('pkp', 'PKP'),
('nonpkp', 'Non PKP')
diff --git a/indoteknik_custom/models/sale_order_line.py b/indoteknik_custom/models/sale_order_line.py
index 5e01067a..978b1f69 100644
--- a/indoteknik_custom/models/sale_order_line.py
+++ b/indoteknik_custom/models/sale_order_line.py
@@ -251,12 +251,9 @@ class SaleOrderLine(models.Model):
# purchase_price = self.env['purchase.pricelist'].search(
# query, limit=1, order='count_trx_po desc, count_trx_po_vendor desc')
price, taxes, vendor_id = self._get_purchase_price(line.product_id)
- line.vendor_md_id = vendor_id
line.vendor_id = vendor_id
- line.margin_md = line.item_percent_margin
line.tax_id = line.order_id.sales_tax_id
# price, taxes = line._get_valid_purchase_price(purchase_price)
- line.purchase_price_md = price
line.purchase_price = price
line.purchase_tax_id = taxes
@@ -270,6 +267,14 @@ class SaleOrderLine(models.Model):
line.name = line_name
line.weight = line.product_id.weight
+ @api.constrains('vendor_id')
+ def _check_vendor_id(self):
+ for line in self:
+ price, taxes, vendor_id = self._get_purchase_price(line.product_id)
+ line.vendor_md_id = vendor_id if vendor_id else None
+ line.margin_md = line.item_percent_margin
+ line.purchase_price_md = price
+
def compute_delivery_amt_line(self):
for line in self:
try:
diff --git a/indoteknik_custom/models/stock_picking.py b/indoteknik_custom/models/stock_picking.py
index 4c9d7658..1906dae0 100644
--- a/indoteknik_custom/models/stock_picking.py
+++ b/indoteknik_custom/models/stock_picking.py
@@ -192,9 +192,9 @@ class StockPicking(models.Model):
else:
raise UserError(f"Error saat mengirim ke Biteship: {response.content}")
- @api.constrains('driver_departure_date')
- def constrains_driver_departure_date(self):
- self.date_doc_kirim = self.driver_departure_date
+ # @api.constrains('driver_departure_date')
+ # def constrains_driver_departure_date(self):
+ # self.date_doc_kirim = self.driver_departure_date
@api.constrains('arrival_time')
def constrains_arrival_time(self):
@@ -246,25 +246,22 @@ class StockPicking(models.Model):
# break
def check_state_reserve(self):
- picking = self.search([
+ pickings = self.search([
('state', 'not in', ['cancel', 'draft', 'done']),
('picking_type_code', '=', 'outgoing')
- ])
+ ])
- for data in picking:
- fullfilment = self.env['sales.order.fullfillment'].search([
- ('sales_order_id', '=', data.sale_id.id)
+ for picking in pickings:
+ fullfillments = self.env['sales.order.fullfillment'].search([
+ ('sales_order_id', '=', picking.sale_id.id)
])
-
- data.state_reserve = 'ready'
- if not data.date_reserved:
- data.date_reserved = datetime.datetime.utcnow()
-
- for rec in fullfilment:
- if rec.reserved_from not in ['Inventory On Hand', 'Reserved from stock', 'Free Stock']:
- data.state_reserve = 'waiting'
- data.date_reserved = ''
- break
+
+ picking.state_reserve = 'ready'
+ picking.date_reserved = picking.date_reserved or datetime.datetime.utcnow()
+
+ if any(rec.reserved_from not in ['Inventory On Hand', 'Reserved from stock', 'Free Stock'] for rec in fullfillments):
+ picking.state_reserve = 'waiting'
+ picking.date_reserved = ''
def _create_approval_notification(self, approval_role):
title = 'Warning'
diff --git a/indoteknik_custom/models/website_user_cart.py b/indoteknik_custom/models/website_user_cart.py
index fbcb0aa4..6cb282f8 100644
--- a/indoteknik_custom/models/website_user_cart.py
+++ b/indoteknik_custom/models/website_user_cart.py
@@ -93,45 +93,32 @@ class WebsiteUserCart(models.Model):
def get_product_by_user(self, user_id, selected=False, source=False):
user_id = int(user_id)
-
+
if source == 'buy':
source = ['buy']
else:
source = ['add_to_cart', 'buy']
parameters = [
- ('user_id', '=', user_id),
+ ('user_id', '=', user_id),
('source', 'in', source)
]
-
- if selected:
- parameters.append(('is_selected', '=', True))
-
carts = self.search(parameters)
- products_active = []
- products_inactive = []
+
for cart in carts:
if cart.product_id:
price = cart.product_id._v2_get_website_price_include_tax()
- if cart.product_id.active and price > 0:
- product = cart.with_context(price_for="web").get_products()
- for product_active in product:
- products_active.append(product_active)
- else:
- product_inactives = cart.with_context(price_for="web").get_products()
- for inactives in product_inactives:
- products_inactive.append(inactives)
- else:
- program = cart.with_context(price_for="web").get_products()
- for programs in program:
- products_active.append(programs)
- data = {
- 'product_total': self.search_count(parameters),
- 'products': products_active,
- 'products_inactive': products_inactive
- }
- products = carts.get_products()
- return products_active
+ if not cart.product_id.active or price < 1:
+ cart.is_selected = False
+
+ if selected:
+ parameters.append(('is_selected', '=', True))
+
+ products_active = self.search(parameters)
+
+ products = products_active.get_products()
+
+ return products
def get_user_checkout(self, user_id, voucher=False, voucher_shipping=False, source=False):
products = self.get_product_by_user(user_id=user_id, selected=True, source=source)
diff --git a/indoteknik_custom/views/requisition.xml b/indoteknik_custom/views/requisition.xml
index b704baaf..a866690d 100644
--- a/indoteknik_custom/views/requisition.xml
+++ b/indoteknik_custom/views/requisition.xml
@@ -50,6 +50,13 @@
<field name="model">requisition</field>
<field name="arch" type="xml">
<form>
+ <header>
+ <button name="button_approve"
+ string="Approve"
+ type="object"
+ class="mr-2 oe_highlight"
+ />
+ </header>
<sheet string="Requisition">
<div class="oe_button_box" name="button_box"/>
<group>