summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorit-fixcomart <it@fixcomart.co.id>2024-08-14 16:12:14 +0700
committerit-fixcomart <it@fixcomart.co.id>2024-08-14 16:12:14 +0700
commitd47eb069978ce67bce1a19b6c824a53ca3d68801 (patch)
tree2427f680d68c8b136531d392eb36cf4262c7d35b
parent2513b765773fca587dbd298e77732d2d005949c8 (diff)
parentd4df708e5195e1c0c3b8e0ad90b7518e5d4d48c2 (diff)
<iman> Merge branch 'production' of https://bitbucket.org/altafixco/indoteknik-addons into feature/tracking-order
# Please enter a commit message to explain why this merge is necessary, # especially if it merges an updated upstream into a topic branch. # # Lines starting with '#' will be ignored, and an empty message aborts # the commit.
-rwxr-xr-xindoteknik_custom/__manifest__.py3
-rwxr-xr-xindoteknik_custom/models/__init__.py1
-rw-r--r--indoteknik_custom/models/account_move_due_extension.py1
-rw-r--r--indoteknik_custom/models/approval_date_doc.py49
-rw-r--r--indoteknik_custom/models/automatic_purchase.py2
-rw-r--r--indoteknik_custom/models/purchasing_job.py33
-rw-r--r--indoteknik_custom/models/report_logbook_bill.py3
-rw-r--r--indoteknik_custom/models/res_partner.py26
-rwxr-xr-xindoteknik_custom/models/sale_order.py104
-rw-r--r--indoteknik_custom/models/sale_order_line.py146
-rw-r--r--indoteknik_custom/models/solr/product_template.py14
-rw-r--r--indoteknik_custom/models/stock_picking.py24
-rw-r--r--indoteknik_custom/models/website_user_cart.py25
-rwxr-xr-xindoteknik_custom/security/ir.model.access.csv1
-rw-r--r--indoteknik_custom/views/airway_bill.xml2
-rw-r--r--indoteknik_custom/views/approval_date_doc.xml61
-rw-r--r--indoteknik_custom/views/ir_sequence.xml10
-rw-r--r--indoteknik_custom/views/partner_payment_term.xml63
-rw-r--r--indoteknik_custom/views/product_sla.xml2
-rw-r--r--indoteknik_custom/views/res_partner.xml17
-rwxr-xr-xindoteknik_custom/views/sale_order.xml6
-rw-r--r--indoteknik_custom/views/stock_picking.xml8
-rw-r--r--indoteknik_custom/views/vendor_payment_term.xml63
23 files changed, 603 insertions, 61 deletions
diff --git a/indoteknik_custom/__manifest__.py b/indoteknik_custom/__manifest__.py
index 32678ef5..8d8e8cec 100755
--- a/indoteknik_custom/__manifest__.py
+++ b/indoteknik_custom/__manifest__.py
@@ -139,6 +139,9 @@
'views/report_logbook_bill.xml',
'views/sale_order_multi_uangmuka_penjualan.xml',
'views/shipment_group.xml',
+ 'views/approval_date_doc.xml',
+ 'views/partner_payment_term.xml',
+ 'views/vendor_payment_term.xml',
'report/report.xml',
'report/report_banner_banner.xml',
'report/report_banner_banner2.xml',
diff --git a/indoteknik_custom/models/__init__.py b/indoteknik_custom/models/__init__.py
index 116354d6..e9ce587c 100755
--- a/indoteknik_custom/models/__init__.py
+++ b/indoteknik_custom/models/__init__.py
@@ -124,3 +124,4 @@ from . import report_logbook_bill
from . import sale_order_multi_uangmuka_penjualan
from . import shipment_group
from . import sales_order_reject
+from . import approval_date_doc
diff --git a/indoteknik_custom/models/account_move_due_extension.py b/indoteknik_custom/models/account_move_due_extension.py
index c9af7f8d..0399c6a2 100644
--- a/indoteknik_custom/models/account_move_due_extension.py
+++ b/indoteknik_custom/models/account_move_due_extension.py
@@ -24,6 +24,7 @@ class DueExtension(models.Model):
('approved', 'Approved'),
], string='Approval Status', readonly=True, copy=False, index=True, tracking=3)
day_extension = fields.Selection([
+ ('1', '1 Hari'),
('3', '3 Hari'),
('7', '7 Hari'),
('14', '14 Hari'),
diff --git a/indoteknik_custom/models/approval_date_doc.py b/indoteknik_custom/models/approval_date_doc.py
new file mode 100644
index 00000000..e00b7416
--- /dev/null
+++ b/indoteknik_custom/models/approval_date_doc.py
@@ -0,0 +1,49 @@
+from odoo import models, api, fields
+from odoo.exceptions import AccessError, UserError, ValidationError
+from datetime import timedelta, date, datetime
+import logging
+
+_logger = logging.getLogger(__name__)
+
+class ApprovalDateDoc(models.Model):
+ _name = "approval.date.doc"
+ _description = "Approval Date Doc"
+ _rec_name = 'number'
+
+ picking_id = fields.Many2one('stock.picking', string='Picking')
+ number = fields.Char(string='Document No', index=True, copy=False, readonly=True, tracking=True)
+ driver_departure_date = fields.Datetime(
+ string='Driver Departure Date',
+ copy=False
+ )
+ state = fields.Selection([('draft', 'Draft'), ('done', 'Done')], string='State', default='draft', tracking=True)
+ approve_date = fields.Datetime(string='Approve Date', copy=False)
+ approve_by = fields.Many2one('res.users', string='Approve By', copy=False)
+ sale_id = fields.Many2one('sale.order', string='Sale Order')
+
+ @api.onchange('picking_id')
+ def onchange_picking_id(self):
+ if self.picking_id:
+ self.sale_id = self.picking_id.sale_id.id
+
+ def check_invoice_so_picking(self):
+ for rec in self:
+ invoice = self.env['account.move'].search_count([('sale_id', '=', rec.picking_id.sale_id.id)])
+
+ if invoice < 1:
+ raise UserError("Sales Order Belum Memiliki Invoice, Anda Bisa Edit Di DO nya langsung")
+
+ def button_approve(self):
+ if not self.env.user.is_accounting:
+ raise UserError("Hanya Accounting Yang Bisa Approve")
+ self.check_invoice_so_picking
+ self.picking_id.driver_departure_date = self.driver_departure_date
+ self.state = 'done'
+ self.approve_date = datetime.utcnow()
+ self.approve_by = self.env.user.id
+
+ @api.model
+ def create(self, vals):
+ vals['number'] = self.env['ir.sequence'].next_by_code('approval.date.doc') or '0'
+ result = super(ApprovalDateDoc, self).create(vals)
+ return result
diff --git a/indoteknik_custom/models/automatic_purchase.py b/indoteknik_custom/models/automatic_purchase.py
index 73416c48..f5b1baf9 100644
--- a/indoteknik_custom/models/automatic_purchase.py
+++ b/indoteknik_custom/models/automatic_purchase.py
@@ -396,7 +396,7 @@ class AutomaticPurchase(models.Model):
domain = [
('product_id', '=', line.product_id.id)
]
- sale = self.env['v.sales.outstanding'].search(domain, limit=1)
+ sale = self.env['v.sales.outstanding'].search(domain, order='sale_order_create_date desc', limit=1)
existing_match = self.env['automatic.purchase.sales.match'].search([
('automatic_purchase_id', '=', self.id),
diff --git a/indoteknik_custom/models/purchasing_job.py b/indoteknik_custom/models/purchasing_job.py
index 373e469a..6e4f239d 100644
--- a/indoteknik_custom/models/purchasing_job.py
+++ b/indoteknik_custom/models/purchasing_job.py
@@ -183,6 +183,7 @@ class OutstandingSales(models.Model):
outgoing = fields.Float(string='Outgoing')
brand = fields.Char(string='Brand')
invoice_partner = fields.Char(string='Invoice Partner')
+ sale_order_create_date = fields.Datetime(string='Sale Order Create Date')
def init(self):
tools.drop_view_if_exists(self.env.cr, self._table)
@@ -199,19 +200,23 @@ class OutstandingSales(models.Model):
so.partner_invoice_id,
sp.origin,
rp2.name as salesperson,
- coalesce(pp.default_code, pt.default_code) as item_code, pt.name as product,
- sm.product_uom_qty as outgoing, xm.x_name as brand, rp.name as invoice_partner
- from stock_move sm
- join stock_picking sp on sp.id = sm.picking_id
- join sale_order_line sol on sol.id = sm.sale_line_id
- join sale_order so on so.id = sol.order_id
- join res_partner rp on rp.id = so.partner_invoice_id
- join res_users ru on ru.id = so.user_id
- join res_partner rp2 on rp2.id = ru.partner_id
- join product_product pp on pp.id = sm.product_id
- join product_template pt on pt.id = pp.product_tmpl_id
- left join x_manufactures xm on xm.id = pt.x_manufacture
- where sp.state in ('draft', 'waiting', 'confirmed', 'assigned')
- and sp.name like '%OUT%'
+ coalesce(pp.default_code, pt.default_code) as item_code,
+ pt.name as product,
+ sm.product_uom_qty as outgoing,
+ xm.x_name as brand,
+ rp.name as invoice_partner,
+ so.create_date as sale_order_create_date
+ from stock_move sm
+ join stock_picking sp on sp.id = sm.picking_id
+ join sale_order_line sol on sol.id = sm.sale_line_id
+ join sale_order so on so.id = sol.order_id
+ join res_partner rp on rp.id = so.partner_invoice_id
+ join res_users ru on ru.id = so.user_id
+ join res_partner rp2 on rp2.id = ru.partner_id
+ join product_product pp on pp.id = sm.product_id
+ join product_template pt on pt.id = pp.product_tmpl_id
+ left join x_manufactures xm on xm.id = pt.x_manufacture
+ where sp.state in ('draft', 'waiting', 'confirmed', 'assigned')
+ and sp.name like '%OUT%'
)
""")
diff --git a/indoteknik_custom/models/report_logbook_bill.py b/indoteknik_custom/models/report_logbook_bill.py
index 9a7c1535..c78d558d 100644
--- a/indoteknik_custom/models/report_logbook_bill.py
+++ b/indoteknik_custom/models/report_logbook_bill.py
@@ -67,12 +67,13 @@ class ReportLogbookBill(models.Model):
self.state = 'terima_sebagian'
else:
self.state = 'terima_semua'
+ self.relation_po_to_logbook()
else:
if self.env.user.is_logistic_approver:
self.state_pengajuan = 'diajukan'
self.date_pengajuan = current_time
self.pengajuan_by = self.env.user.id
- self.relation_po_to_logbook()
+
def relation_po_to_logbook(self):
for line in self.report_logbook_bill_line:
diff --git a/indoteknik_custom/models/res_partner.py b/indoteknik_custom/models/res_partner.py
index 77273610..ac126337 100644
--- a/indoteknik_custom/models/res_partner.py
+++ b/indoteknik_custom/models/res_partner.py
@@ -48,12 +48,27 @@ class ResPartner(models.Model):
user_payment_terms_purchase = fields.Many2one('res.users', string='Users Update Payment Terms')
date_payment_terms_purchase = fields.Datetime(string='Date Update Payment Terms')
+ @api.model
+ def _default_payment_term(self):
+ return self.env.ref('__export__.account_payment_term_26_484409e2').id
+
+ property_payment_term_id = fields.Many2one(
+ 'account.payment.term',
+ string='Payment Terms',
+ default=_default_payment_term
+ )
+
def write(self, vals):
res = super(ResPartner, self).write(vals)
- if 'property_payment_term_id' in vals:
- if not self.env.user.is_accounting and vals['property_payment_term_id'] != 26:
- raise UserError('Hanya Finance Accounting yang dapat merubah payment term')
+ # if 'property_payment_term_id' in vals:
+ # if not self.env.user.is_accounting and vals['property_payment_term_id'] != 26:
+ # raise UserError('Hanya Finance Accounting yang dapat merubah payment term')
+
+ # group_id = self.env.ref('indoteknik_custom.group_role_merchandiser').id
+ # users_in_group = self.env['res.users'].search([('groups_id', 'in', [group_id])])
+ # if self.env.user.id not in users_in_group.mapped('id'):
+ # raise UserError('You name it')
return res
@@ -120,5 +135,10 @@ class ResPartner(models.Model):
if self._name == 'res.partner':
raise UserError('Maaf anda tidak bisa delete contact')
+ @api.onchange('customer_type')
+ def _onchange_customer_type(self):
+ if self.customer_type == 'nonpkp':
+ self.npwp = '00.000.000.0-000.000'
+
diff --git a/indoteknik_custom/models/sale_order.py b/indoteknik_custom/models/sale_order.py
index 44e4a886..0b0a679f 100755
--- a/indoteknik_custom/models/sale_order.py
+++ b/indoteknik_custom/models/sale_order.py
@@ -108,6 +108,7 @@ class SaleOrder(models.Model):
date_driver_arrival = fields.Datetime(string='Arrival Date', compute='_compute_date_kirim', copy=False)
date_driver_departure = fields.Datetime(string='Departure Date', compute='_compute_date_kirim', copy=False)
note_website = fields.Char(string="Note Website")
+ use_button = fields.Boolean(string='Using Calculate Selling Price', copy=False)
def _compute_date_kirim(self):
for rec in self:
@@ -500,6 +501,10 @@ class SaleOrder(models.Model):
raise UserError("Credit Limit pada Master Data Customer harus diisi")
if order.payment_term_id != partner.property_payment_term_id:
raise UserError("Payment Term berbeda pada Master Data Customer")
+ if (partner.customer_type == 'pkp' or order.customer_type == 'pkp') and order.npwp != partner.npwp:
+ raise UserError("NPWP berbeda pada Master Data Customer")
+ if (partner.customer_type == 'pkp' or order.customer_type == 'pkp') and order.sppkp != partner.sppkp:
+ raise UserError("SPPKP berbeda pada Master Data Customer")
if not order.client_order_ref and order.create_date > datetime(2024, 6, 27):
raise UserError("Customer Reference kosong, di isi dengan NO PO jika PO tidak ada mohon ditulis Tanpa PO")
@@ -517,6 +522,10 @@ class SaleOrder(models.Model):
raise UserError("Credit Limit pada Master Data Customer harus diisi")
if order.payment_term_id != partner.property_payment_term_id:
raise UserError("Payment Term berbeda pada Master Data Customer")
+ if (partner.customer_type == 'pkp' or order.customer_type == 'pkp') and order.npwp != partner.npwp:
+ raise UserError("NPWP berbeda pada Master Data Customer")
+ if (partner.customer_type == 'pkp' or order.customer_type == 'pkp') and order.sppkp != partner.sppkp:
+ raise UserError("SPPKP berbeda pada Master Data Customer")
if not order.client_order_ref and order.create_date > datetime(2024, 6, 27):
raise UserError("Customer Reference kosong, di isi dengan NO PO jika PO tidak ada mohon ditulis Tanpa PO")
@@ -834,5 +843,98 @@ class SaleOrder(models.Model):
}
}
+ def calculate_selling_price(self):
+ # ongkos kirim, biaya pihak ketiga calculate @stephan
+ # TODO voucher @stephan
+ # vendor hilangin child di field SO Line @stephan
+ # button pindahin @stephan
+ # last so 1 tahun ke belakang @stephan
+ # pastikan harga beli 1 tahun ke belakang jg
+ # harga yg didapat dari semua kumpulan parent parner dan child nya
+ # counter di klik berapa banyak @stephan
+ for order_line in self.order_line:
+ if not order_line.product_id:
+ continue
+ current_time = datetime.now()
+ delta_time = current_time - timedelta(days=365)
+ delta_time = delta_time.strftime('%Y-%m-%d %H:%M:%S')
+
+ # Initialize partners list with parent_id or partner_id
+ partners = []
+ parent_id = self.partner_id.parent_id or self.partner_id
+
+ # Add all child_ids and the parent itself to partners as IDs
+ partners.extend(parent_id.child_ids.ids)
+ partners.append(parent_id.id)
+
+ rec_purchase_price, rec_taxes_id, rec_vendor_id = order_line._get_purchase_price(order_line.product_id)
+ state = ['sale', 'done']
+ last_so = self.env['sale.order.line'].search([
+ # ('order_id.partner_id.id', '=', order_line.order_id.partner_id.id),
+ ('order_id.partner_id', 'in', partners),
+ ('product_id.id', '=', order_line.product_id.id),
+ ('order_id.state', 'in', state),
+ ('id', '!=', order_line.id),
+ ('order_id.date_order', '>=', delta_time)
+ ], limit=1, order='create_date desc')
+
+ if rec_vendor_id != last_so.vendor_id.id:
+ last_so = self.env['sale.order.line'].search([
+ # ('order_id.partner_id.id', '=', order_line.order_id.partner_id.id),
+ ('order_id.partner_id', 'in', partners),
+ ('product_id.id', '=', order_line.product_id.id),
+ ('order_id.state', 'in', state),
+ ('vendor_id', '=', rec_vendor_id),
+ ('id', '!=', order_line.id),
+ ('order_id.date_order', '>=', delta_time)
+ ], limit=1, order='create_date desc')
+
+ if rec_purchase_price != last_so.purchase_price:
+ rec_taxes = self.env['account.tax'].search([('id', '=', rec_taxes_id)], limit=1)
+ if rec_taxes.price_include:
+ selling_price = (rec_purchase_price / 1.11) / (1 - (last_so.item_percent_margin_without_deduction / 100))
+ else:
+ selling_price = rec_purchase_price / (1 - (last_so.item_percent_margin_without_deduction / 100))
+ tax_id = last_so.tax_id
+ for tax in tax_id:
+ if tax.price_include:
+ selling_price = selling_price + (selling_price*11/100)
+ else:
+ selling_price = selling_price
+ discount = 0
+ elif last_so:
+ selling_price = last_so.price_unit
+ tax_id = last_so.tax_id
+ discount = last_so.discount
+ else:
+ selling_price = order_line.price_unit
+ tax_id = order_line.tax_id
+ discount = order_line.discount
+
+ elif rec_vendor_id == order_line.vendor_id.id and rec_purchase_price != last_so.purchase_price:
+ rec_taxes = self.env['account.tax'].search([('id', '=', rec_taxes_id)], limit=1)
+ if rec_taxes.price_include:
+ selling_price = (rec_purchase_price / 1.11) / (1 - (last_so.item_percent_margin_without_deduction / 100))
+ else:
+ selling_price = rec_purchase_price / (1 - (last_so.item_percent_margin_without_deduction / 100))
+ tax_id = last_so.tax_id
+ for tax in tax_id:
+ if tax.price_include:
+ selling_price = selling_price + (selling_price*11/100)
+ else:
+ selling_price = selling_price
+ discount = 0
+
+ elif last_so:
+ selling_price = last_so.price_unit
+ tax_id = last_so.tax_id
+ discount = last_so.discount
-
+ else:
+ selling_price = order_line.price_unit
+ tax_id = order_line.tax_id
+ discount = order_line.discount
+ order_line.price_unit = selling_price
+ order_line.tax_id = tax_id
+ order_line.discount = discount
+ order_line.order_id.use_button = True
diff --git a/indoteknik_custom/models/sale_order_line.py b/indoteknik_custom/models/sale_order_line.py
index 1f90b821..a64a744c 100644
--- a/indoteknik_custom/models/sale_order_line.py
+++ b/indoteknik_custom/models/sale_order_line.py
@@ -1,6 +1,6 @@
from odoo import fields, models, api, _
from odoo.exceptions import UserError
-from datetime import datetime
+from datetime import datetime, timedelta
class SaleOrderLine(models.Model):
@@ -30,6 +30,7 @@ class SaleOrderLine(models.Model):
amount_voucher_disc = fields.Float(string='Voucher Discount')
qty_reserved = fields.Float(string='Qty Reserved', compute='_compute_qty_reserved')
reserved_from = fields.Char(string='Reserved From', copy=False)
+ item_percent_margin_without_deduction = fields.Float('%Margin', compute='_compute_item_margin_without_deduction')
@api.constrains('note_procurement')
def note_procurement_to_apo(self):
@@ -40,8 +41,6 @@ class SaleOrderLine(models.Model):
for match_so in matches_so:
match_so.note_procurement = line.note_procurement
-
-
@api.onchange('product_uom', 'product_uom_qty')
def product_uom_change(self):
@@ -63,9 +62,9 @@ class SaleOrderLine(models.Model):
line.qty_reserved = reserved_qty
def _compute_reserved_from(self):
- for line in self:
- report_stock_forecasted = self.env['report.stock.report_product_product_replenishment']
- report_stock_forecasted._get_report_data(False, [line.product_id.id])
+ for line in self:
+ report_stock_forecasted = self.env['report.stock.report_product_product_replenishment']
+ report_stock_forecasted._get_report_data(False, [line.product_id.id])
def _compute_vendor_subtotal(self):
for line in self:
@@ -74,6 +73,28 @@ class SaleOrderLine(models.Model):
else:
line.vendor_subtotal = 0
+ def _compute_item_margin_without_deduction(self):
+ for line in self:
+ if not line.product_id or line.product_id.type == 'service' \
+ or line.price_unit <= 0 or line.product_uom_qty <= 0 \
+ or not line.vendor_id:
+ line.item_percent_margin_without_deduction = 0
+ continue
+ # calculate margin without tax
+ sales_price = line.price_reduce_taxexcl * line.product_uom_qty
+
+ purchase_price = line.purchase_price
+ if line.purchase_tax_id.price_include:
+ purchase_price = line.purchase_price / 1.11
+
+ purchase_price = purchase_price * line.product_uom_qty
+ margin_per_item = sales_price - purchase_price
+
+ if sales_price > 0:
+ line.item_percent_margin_without_deduction = round((margin_per_item / sales_price), 2) * 100
+ else:
+ line.item_percent_margin_without_deduction = 0
+
def compute_item_margin(self):
for line in self:
if not line.product_id or line.product_id.type == 'service' \
@@ -105,59 +126,128 @@ class SaleOrderLine(models.Model):
@api.onchange('vendor_id')
def onchange_vendor_id(self):
+ # TODO : need to change this logic @stephan
if not self.product_id or self.product_id.type == 'service':
return
elif self.product_id.categ_id.id == 34: # finish good / manufacturing only
cost = self.product_id.standard_price
self.purchase_price = cost
elif self.product_id.x_manufacture.override_vendor_id:
- purchase_price = self.env['purchase.pricelist'].search(
- [('vendor_id', '=', self.product_id.x_manufacture.override_vendor_id.id),
- ('product_id', '=', self.product_id.id)],
- limit=1, order='count_trx_po desc, count_trx_po_vendor desc')
- price, taxes = self._get_valid_purchase_price(purchase_price)
- self.purchase_price = price
- self.purchase_tax_id = taxes
- else:
- purchase_price = self.env['purchase.pricelist'].search(
- [('vendor_id', '=', self.vendor_id.id), ('product_id', '=', self.product_id.id)],
- limit=1, order='count_trx_po desc, count_trx_po_vendor desc')
- price, taxes = self._get_valid_purchase_price(purchase_price)
+ # purchase_price = self.env['purchase.pricelist'].search(
+ # [('vendor_id', '=', self.product_id.x_manufacture.override_vendor_id.id),
+ # ('product_id', '=', self.product_id.id)],
+ # limit=1, order='count_trx_po desc, count_trx_po_vendor desc')
+ price, taxes, vendor_id = self._get_purchase_price_by_vendor(self.product_id, self.vendor_id)
self.purchase_price = price
self.purchase_tax_id = taxes
+ # else:
+ # purchase_price = self.env['purchase.pricelist'].search(
+ # [('vendor_id', '=', self.vendor_id.id), ('product_id', '=', self.product_id.id)],
+ # limit=1, order='count_trx_po desc, count_trx_po_vendor desc')
+ # price, taxes = self._get_valid_purchase_price(purchase_price)
+ # self.purchase_price = price
+ # self.purchase_tax_id = taxes
+
+ # def _calculate_selling_price(self):
+ # rec_purchase_price, rec_taxes, rec_vendor_id = self._get_purchase_price(self.product_id)
+ # state = ['sale', 'done']
+ # last_so = self.env['sale.order.line'].search([
+ # ('order_id.partner_id.id', '=', self.order_id.partner_id.id),
+ # ('product_id.id', '=', self.product_id.id),
+ # ('order_id.state', 'in', state)
+ # ], limit=1, order='create_date desc')
+ # # if rec_vendor_id == self.vendor_id and rec_purchase_price == last_so.purchase_price:
+ # # selling_price = last_so.price_unit
+ # # tax_id = last_so.tax_id
+ # if rec_vendor_id == self.vendor_id and rec_purchase_price != last_so.purchase_price:
+ # if rec_taxes.price_include:
+ # selling_price = (rec_purchase_price/1.11) / (1-(last_so.line_item_margin / 100))
+ # else:
+ # selling_price = rec_purchase_price / (1-(last_so.line_item_margin / 100))
+ # tax_id = last_so.tax_id
+ # elif rec_vendor_id != last_so.vendor_id:
+ # last_so = self.env['sale.order.line'].search([
+ # ('order_id.partner_id.id', '=', self.order_id.partner_id.id),
+ # ('product_id.id', '=', self.product_id.id),
+ # ('state', 'in', state),
+ # ('vendor_id', '=', rec_vendor_id)
+ # ], limit=1, order='order_id.date_order desc')
+ # selling_price = last_so.price_unit
+ # tax_id = last_so.tax_id
+ # else:
+ # selling_price = last_so.price_unit
+ # tax_id = last_so.tax_id
+ # self.price_unit = selling_price
+ # self.tax_id = tax_id
+
+ def _get_purchase_price(self, product_id):
+ purchase_price = self.env['purchase.pricelist'].search(
+ [('product_id', '=', product_id.id),
+ ('is_winner', '=', True)],
+ limit=1)
+
+ return self._get_valid_purchase_price(purchase_price)
+
+ def _get_purchase_price_by_vendor(self, product_id, vendor_id):
+ purchase_price = self.env['purchase.pricelist'].search(
+ [('product_id', '=', product_id.id),
+ ('vendor_id', '=', vendor_id.id),
+ # ('is_winner', '=', True)
+ ],
+ limit=1)
+
+ return self._get_valid_purchase_price(purchase_price)
def _get_valid_purchase_price(self, purchase_price):
+ current_time = datetime.now()
+ delta_time = current_time - timedelta(days=365)
+ # delta_time = delta_time.strftime('%Y-%m-%d %H:%M:%S')
+
price = 0
taxes = ''
+ vendor_id = ''
human_last_update = purchase_price.human_last_update or datetime.min
system_last_update = purchase_price.system_last_update or datetime.min
- if purchase_price.taxes_product_id.type_tax_use == 'purchase':
+ if purchase_price.taxes_product_id.type_tax_use == 'purchase':
price = purchase_price.product_price
taxes = purchase_price.taxes_product_id.id
+ vendor_id = purchase_price.vendor_id.id
+ if delta_time > human_last_update:
+ price = 0
+ taxes = ''
+ vendor_id = ''
if system_last_update > human_last_update:
if purchase_price.taxes_system_id.type_tax_use == 'purchase':
price = purchase_price.system_price
taxes = purchase_price.taxes_system_id.id
+ vendor_id = purchase_price.vendor_id.id
+ if delta_time > system_last_update:
+ price = 0
+ taxes = ''
+ vendor_id = ''
- return price, taxes
+ return price, taxes, vendor_id
@api.onchange('product_id')
def product_id_change(self):
+ # need to change purchase price logic @stephan
super(SaleOrderLine, self).product_id_change()
for line in self:
if line.product_id and line.product_id.type == 'product':
- query = [('product_id', '=', line.product_id.id)]
- if line.product_id.x_manufacture.override_vendor_id:
- query = [('product_id', '=', line.product_id.id),
- ('vendor_id', '=', line.product_id.x_manufacture.override_vendor_id.id)]
- purchase_price = self.env['purchase.pricelist'].search(
- query, limit=1, order='count_trx_po desc, count_trx_po_vendor desc')
- line.vendor_id = purchase_price.vendor_id
+ # query = [('product_id', '=', line.product_id.id)]
+ # if line.product_id.x_manufacture.override_vendor_id:
+ # query = [('product_id', '=', line.product_id.id),
+ # ('vendor_id', '=', line.product_id.x_manufacture.override_vendor_id.id)]
+ # 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_id = vendor_id
line.tax_id = line.order_id.sales_tax_id
- price, taxes = line._get_valid_purchase_price(purchase_price)
+ # price, taxes = line._get_valid_purchase_price(purchase_price)
line.purchase_price = price
+ line.purchase_tax_id = taxes
attribute_values = line.product_id.product_template_attribute_value_ids.mapped('name')
attribute_values_str = ', '.join(attribute_values) if attribute_values else ''
diff --git a/indoteknik_custom/models/solr/product_template.py b/indoteknik_custom/models/solr/product_template.py
index 892e7334..6ad49af7 100644
--- a/indoteknik_custom/models/solr/product_template.py
+++ b/indoteknik_custom/models/solr/product_template.py
@@ -68,7 +68,17 @@ class ProductTemplate(models.Model):
# Mengumpulkan semua kategori
category_ids = [category.id for category in template.public_categ_ids]
category_names = [category.name for category in template.public_categ_ids]
-
+
+ # Check if the product's inventory location is in ID 57 or 83
+ target_locations = [57, 83]
+ stock_quant = self.env['stock.quant'].search([
+ ('product_id', 'in', template.product_variant_ids.ids),
+ ('location_id', 'in', target_locations)
+ ])
+
+ is_in_bu = bool(stock_quant)
+ on_hand_qty = sum(stock_quant.mapped('quantity')) if stock_quant else 0
+
document = solr_model.get_doc('product', template.id)
document.update({
"id": template.id,
@@ -99,6 +109,8 @@ class ProductTemplate(models.Model):
'sni_b': template.unpublished,
'tkdn_b': template.unpublished,
"qty_sold_f": template.qty_sold,
+ "is_in_bu_b": is_in_bu,
+ "on_hand_qty_i": on_hand_qty,
"voucher_pastihemat" : {
"min_purchase" : voucher.min_purchase_amount or 0,
"discount_type" : voucher.discount_type or '',
diff --git a/indoteknik_custom/models/stock_picking.py b/indoteknik_custom/models/stock_picking.py
index c151a543..5029a770 100644
--- a/indoteknik_custom/models/stock_picking.py
+++ b/indoteknik_custom/models/stock_picking.py
@@ -26,7 +26,10 @@ class StockPicking(models.Model):
# Delivery Order
driver_departure_date = fields.Datetime(
string='Driver Departure Date',
- readonly=True,
+ copy=False
+ )
+ arrival_time = fields.Datetime(
+ string='Jam Kedatangan',
copy=False
)
driver_arrival_date = fields.Datetime(
@@ -91,6 +94,21 @@ class StockPicking(models.Model):
date_availability = fields.Datetime(string="Date Availability", copy=False, tracking=True)
sale_order = fields.Char(string='Matches SO', copy=False)
printed_sj = fields.Boolean('Printed Surat Jalan', help='flag which is internal use or not')
+ invoice_status = fields.Selection([
+ ('upselling', 'Upselling Opportunity'),
+ ('invoiced', 'Fully Invoiced'),
+ ('to invoice', 'To Invoice'),
+ ('no', 'Nothing to Invoice')
+ ], string='Invoice Status', related="sale_id.invoice_status")
+
+ @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):
+ if self.arrival_time > datetime.datetime.utcnow():
+ raise UserError('Jam kedatangan harus kurang dari Effective Date')
def reset_status_printed(self):
for rec in self:
@@ -341,6 +359,9 @@ class StockPicking(models.Model):
if not self.picking_code:
self.picking_code = self.env['ir.sequence'].next_by_code('stock.picking.code') or '0'
+ if not self.arrival_time and 'BU/IN/' in self.name:
+ raise UserError('Jam Kedatangan harus diisi')
+
if self.picking_type_id.code == 'incoming' and self.group_id.id == False and self.is_internal_use == False:
raise UserError(_('Tidak bisa Validate jika tidak dari Document SO / PO'))
@@ -372,6 +393,7 @@ class StockPicking(models.Model):
res = super(StockPicking, self).button_validate()
self.calculate_line_no()
+ self.date_done = datetime.datetime.utcnow()
return res
@api.model
diff --git a/indoteknik_custom/models/website_user_cart.py b/indoteknik_custom/models/website_user_cart.py
index dd3f87e6..10821cd3 100644
--- a/indoteknik_custom/models/website_user_cart.py
+++ b/indoteknik_custom/models/website_user_cart.py
@@ -24,16 +24,31 @@ class WebsiteUserCart(models.Model):
def get_product(self):
res = {
- 'cart_id': self.id,
- 'quantity': self.qty,
+ 'cart_id': self.id,
+ 'quantity': self.qty,
'selected': self.is_selected,
'can_buy': True
}
-
+
if self.product_id:
res['cart_type'] = 'product'
product = self.product_id.v2_api_single_response(self.product_id)
res.update(product)
+
+ # Check if the product's inventory location is in ID 57 or 83
+ target_locations = [57, 83]
+ stock_quant = self.env['stock.quant'].search([
+ ('product_id', '=', self.product_id.id),
+ ('location_id', 'in', target_locations)
+ ])
+
+ if stock_quant:
+ res['is_in_bu'] = True
+ res['on_hand_qty'] = sum(stock_quant.mapped('quantity'))
+ else:
+ res['is_in_bu'] = False
+ res['on_hand_qty'] = 0
+
flashsales = self.product_id._get_active_flash_sale()
res['has_flashsale'] = True if len(flashsales) > 0 else False
elif self.program_line_id:
@@ -48,9 +63,9 @@ class WebsiteUserCart(models.Model):
res['can_buy'] = False
res['subtotal'] = self.qty * res['price']['price_discount']
-
+
return res
-
+
def get_products(self):
products = [x.get_product() for x in self]
diff --git a/indoteknik_custom/security/ir.model.access.csv b/indoteknik_custom/security/ir.model.access.csv
index 95ad57f0..5e7554a5 100755
--- a/indoteknik_custom/security/ir.model.access.csv
+++ b/indoteknik_custom/security/ir.model.access.csv
@@ -133,3 +133,4 @@ access_sale_order_multi_uangmuka_penjualan,access.sale.order.multi_uangmuka_penj
access_shipment_group,access.shipment.group,model_shipment_group,,1,1,1,1
access_shipment_group_line,access.shipment.group.line,model_shipment_group_line,,1,1,1,1
access_sales_order_reject,access.sales.order.reject,model_sales_order_reject,,1,1,1,1
+access_approval_date_doc,access.approval.date.doc,model_approval_date_doc,,1,1,1,1
diff --git a/indoteknik_custom/views/airway_bill.xml b/indoteknik_custom/views/airway_bill.xml
index 015f20f2..626a6763 100644
--- a/indoteknik_custom/views/airway_bill.xml
+++ b/indoteknik_custom/views/airway_bill.xml
@@ -94,7 +94,7 @@
<field name="code">model._fetch()</field>
<field name="state">code</field>
<field name="priority">75</field>
- <field name="active">True</field>
+ <field name="active">False</field>
</record>
<menuitem id="menu_airway_bill"
diff --git a/indoteknik_custom/views/approval_date_doc.xml b/indoteknik_custom/views/approval_date_doc.xml
new file mode 100644
index 00000000..d6a70763
--- /dev/null
+++ b/indoteknik_custom/views/approval_date_doc.xml
@@ -0,0 +1,61 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<odoo>
+ <record id="approval_date_doc_tree" model="ir.ui.view">
+ <field name="name">approval.date.doc.tree</field>
+ <field name="model">approval.date.doc</field>
+ <field name="arch" type="xml">
+ <tree>
+ <field name="number"/>
+ <field name="picking_id"/>
+ <field name="sale_id"/>
+ <field name="driver_departure_date"/>
+ <field name="state"/>
+ <field name="approve_date"/>
+ <field name="approve_by"/>
+ </tree>
+ </field>
+ </record>
+
+ <record id="approval_date_doc_form" model="ir.ui.view">
+ <field name="name">approval.date.doc.form</field>
+ <field name="model">approval.date.doc</field>
+ <field name="arch" type="xml">
+ <form>
+ <header>
+ <button name="button_approve"
+ string="Approve"
+ type="object"
+ attrs="{'invisible': [('state', '=', 'done')]}"
+ />
+ </header>
+ <sheet string="Approval Date Doc">
+ <group>
+ <group>
+ <field name="number"/>
+ <field name="picking_id"/>
+ <field name="sale_id"/>
+ <field name="driver_departure_date"/>
+ <field name="approve_date"/>
+ <field name="approve_by"/>
+ <field name="state" readonly="1"/>
+ </group>
+ </group>
+ </sheet>
+ </form>
+ </field>
+ </record>
+
+ <record id="approval_date_doc_action" model="ir.actions.act_window">
+ <field name="name">Approval Date Doc</field>
+ <field name="type">ir.actions.act_window</field>
+ <field name="res_model">approval.date.doc</field>
+ <field name="view_mode">tree,form</field>
+ </record>
+
+ <menuitem id="menu_approval_date_doc" name="Approval Date Doc"
+ parent="account.menu_finance_receivables"
+ action="approval_date_doc_action"
+ sequence="100"
+ />
+
+</odoo> \ No newline at end of file
diff --git a/indoteknik_custom/views/ir_sequence.xml b/indoteknik_custom/views/ir_sequence.xml
index b4fb5c0c..b2768c71 100644
--- a/indoteknik_custom/views/ir_sequence.xml
+++ b/indoteknik_custom/views/ir_sequence.xml
@@ -11,6 +11,16 @@
<field name="number_increment">1</field>
</record>
+ <record id="sequence_date_doc" model="ir.sequence">
+ <field name="name">Approval Date Doc</field>
+ <field name="code">approval.date.doc</field>
+ <field name="active">TRUE</field>
+ <field name="prefix">ADD/%(year)s/</field>
+ <field name="padding">5</field>
+ <field name="number_next">1</field>
+ <field name="number_increment">1</field>
+ </record>
+
<record id="sequence_logbook_sj" model="ir.sequence">
<field name="name">Logbook SJ</field>
<field name="code">report.logbook.sj</field>
diff --git a/indoteknik_custom/views/partner_payment_term.xml b/indoteknik_custom/views/partner_payment_term.xml
new file mode 100644
index 00000000..433cac3e
--- /dev/null
+++ b/indoteknik_custom/views/partner_payment_term.xml
@@ -0,0 +1,63 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<odoo>
+ <record id="partner_payment_term_tree" model="ir.ui.view">
+ <field name="name">partner.payment.term.tree</field>
+ <field name="model">res.partner</field>
+ <field name="arch" type="xml">
+ <tree>
+ <field name="display_name"/>
+ <field name="name"/>
+ <field name="parent_id"/>
+ <field name="property_payment_term_id"/>
+ </tree>
+ </field>
+ </record>
+
+ <record id="partner_payment_term_form" model="ir.ui.view">
+ <field name="name">partner.payment.term.form</field>
+ <field name="model">res.partner</field>
+ <field name="arch" type="xml">
+ <form>
+ <sheet>
+ <group>
+ <group>
+ <field name="name"/>
+ <field name="parent_id" readonly="1"/>
+ <field name="property_payment_term_id"/>
+ </group>
+ </group>
+ </sheet>
+ </form>
+ </field>
+ </record>
+
+ <record id="view_partner_payment_term_filter" model="ir.ui.view">
+ <field name="name">partner.payment.term.list.select</field>
+ <field name="model">res.partner</field>
+ <field name="priority" eval="15"/>
+ <field name="arch" type="xml">
+ <search string="Name">
+ <field name="display_name"/>
+ <field name="name"/>
+ <field name="parent_id"/>
+ </search>
+ </field>
+ </record>
+
+ <record id="partner_payment_term_action" model="ir.actions.act_window">
+ <field name="name">Partner Payment Term</field>
+ <field name="type">ir.actions.act_window</field>
+ <field name="res_model">res.partner</field>
+ <field name="search_view_id" ref="view_partner_payment_term_filter"/>
+ <field name="view_mode">tree,form</field>
+ <field name="view_id" ref="partner_payment_term_tree"/>
+ <field name="view_ids" eval="[(5, 0, 0), (0, 0, {'view_mode': 'tree', 'view_id': ref('partner_payment_term_tree')}), (0, 0, {'view_mode': 'form', 'view_id': ref('partner_payment_term_form')})]"/>
+ </record>
+
+ <menuitem id="menu_partner_payment_term_acct"
+ name="Partner Payment Term"
+ action="partner_payment_term_action"
+ parent="account.menu_finance_entries"
+ sequence="115"
+ />
+</odoo> \ No newline at end of file
diff --git a/indoteknik_custom/views/product_sla.xml b/indoteknik_custom/views/product_sla.xml
index d0d3f84a..8b0e874b 100644
--- a/indoteknik_custom/views/product_sla.xml
+++ b/indoteknik_custom/views/product_sla.xml
@@ -48,7 +48,7 @@
<field name="code">model.generate_product_variant_id_sla(limit=150)</field>
<field name="state">code</field>
<field name="priority">100</field>
- <field name="active">True</field>
+ <field name="active">False</field>
</record>
<menuitem id="menu_product_sla"
diff --git a/indoteknik_custom/views/res_partner.xml b/indoteknik_custom/views/res_partner.xml
index b928b046..d77e09b8 100644
--- a/indoteknik_custom/views/res_partner.xml
+++ b/indoteknik_custom/views/res_partner.xml
@@ -26,8 +26,17 @@
<field name="pareto_status"/>
<field name="digital_invoice_tax"/>
</field>
+ <field name="nama_wajib_pajak" position="attributes">
+ <attribute name="required">1</attribute>
+ </field>
+ <field name="npwp" position="attributes">
+ <attribute name="required">1</attribute>
+ </field>
+ <field name="alamat_lengkap_text" position="attributes">
+ <attribute name="required">1</attribute>
+ </field>
<field name="npwp" position="before">
- <field name="customer_type"/>
+ <field name="customer_type" required="1"/>
</field>
<field name="is_berikat" position="after">
<field name="pakta_integritas"/>
@@ -47,6 +56,12 @@
<field name="main_parent_id" invisible="1" />
<field name="site_id" attrs="{'readonly': [('parent_id', '=', False)]}" domain="[('partner_id', '=', main_parent_id)]" context="{'default_partner_id': active_id}" />
</xpath>
+ <xpath expr="//field[@name='property_payment_term_id']" position="attributes">
+ <attribute name="readonly">1</attribute>
+ </xpath>
+ <xpath expr="//field[@name='property_supplier_payment_term_id']" position="attributes">
+ <attribute name="readonly">1</attribute>
+ </xpath>
</field>
</record>
</data>
diff --git a/indoteknik_custom/views/sale_order.xml b/indoteknik_custom/views/sale_order.xml
index 04f21d83..1257ff85 100755
--- a/indoteknik_custom/views/sale_order.xml
+++ b/indoteknik_custom/views/sale_order.xml
@@ -43,6 +43,10 @@
attrs="{'invisible': ['|', ('applied_voucher_id', '=', False), ('state', 'not in', ['draft','sent'])]}"
/>
</div>
+ <button name="calculate_selling_price"
+ string="Calculate Selling Price"
+ type="object"
+ />
</field>
<field name="source_id" position="attributes">
<attribute name="invisible">1</attribute>
@@ -96,7 +100,7 @@
</attribute>
</xpath>
<xpath expr="//form/sheet/notebook/page/field[@name='order_line']/tree/field[@name='price_total']" position="after">
- <field name="vendor_id" attrs="{'readonly': [('parent.approval_status', '=', 'approved')]}"/>
+ <field name="vendor_id" attrs="{'readonly': [('parent.approval_status', '=', 'approved')]}" domain="[('parent_id', '=', False)]"/>
<field name="purchase_price" attrs="
{
'readonly': [
diff --git a/indoteknik_custom/views/stock_picking.xml b/indoteknik_custom/views/stock_picking.xml
index 7567dda2..899d29eb 100644
--- a/indoteknik_custom/views/stock_picking.xml
+++ b/indoteknik_custom/views/stock_picking.xml
@@ -68,10 +68,14 @@
<field name="partner_id" position="after">
<field name="real_shipping_id"/>
</field>
+ <field name="date_done" position="after">
+ <field name="arrival_time"/>
+ </field>
<field name="origin" position="after">
<field name="purchase_id"/>
<field name="sale_order"/>
- <field name="date_doc_kirim"/>
+ <field name="invoice_status"/>
+ <field name="date_doc_kirim" attrs="{'readonly':[('invoice_status', '=', 'invoiced')]}"/>
<field name="summary_qty_operation"/>
<field name="count_line_operation"/>
<field name="account_id"
@@ -118,7 +122,7 @@
<group>
<group>
<field name="note_logistic"/>
- <field name="driver_departure_date"/>
+ <field name="driver_departure_date" attrs="{'readonly':[('invoice_status', '=', 'invoiced')]}"/>
<field name="driver_arrival_date"/>
<field name="delivery_tracking_no"/>
<field name="driver_id"/>
diff --git a/indoteknik_custom/views/vendor_payment_term.xml b/indoteknik_custom/views/vendor_payment_term.xml
new file mode 100644
index 00000000..e0e96388
--- /dev/null
+++ b/indoteknik_custom/views/vendor_payment_term.xml
@@ -0,0 +1,63 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<odoo>
+ <record id="vendor_payment_term_tree" model="ir.ui.view">
+ <field name="name">vendor.payment.term.tree</field>
+ <field name="model">res.partner</field>
+ <field name="arch" type="xml">
+ <tree>
+ <field name="display_name"/>
+ <field name="name"/>
+ <field name="parent_id"/>
+ <field name="property_supplier_payment_term_id"/>
+ </tree>
+ </field>
+ </record>
+
+ <record id="vendor_payment_term_form" model="ir.ui.view">
+ <field name="name">vendor.payment.term.form</field>
+ <field name="model">res.partner</field>
+ <field name="arch" type="xml">
+ <form>
+ <sheet>
+ <group>
+ <group>
+ <field name="name"/>
+ <field name="parent_id" readonly="1"/>
+ <field name="property_supplier_payment_term_id"/>
+ </group>
+ </group>
+ </sheet>
+ </form>
+ </field>
+ </record>
+
+ <record id="view_vendor_payment_term_filter" model="ir.ui.view">
+ <field name="name">vendor.payment.term.list.select</field>
+ <field name="model">res.partner</field>
+ <field name="priority" eval="15"/>
+ <field name="arch" type="xml">
+ <search string="Name">
+ <field name="display_name"/>
+ <field name="name"/>
+ <field name="parent_id"/>
+ </search>
+ </field>
+ </record>
+
+ <record id="vendor_payment_term_action" model="ir.actions.act_window">
+ <field name="name">Vendor Payment Term</field>
+ <field name="type">ir.actions.act_window</field>
+ <field name="res_model">res.partner</field>
+ <field name="search_view_id" ref="view_vendor_payment_term_filter"/>
+ <field name="view_mode">tree,form</field>
+ <field name="view_id" ref="vendor_payment_term_tree"/>
+ <field name="view_ids" eval="[(5, 0, 0), (0, 0, {'view_mode': 'tree', 'view_id': ref('vendor_payment_term_tree')}), (0, 0, {'view_mode': 'form', 'view_id': ref('vendor_payment_term_form')})]"/>
+ </record>
+
+ <menuitem id="menu_vendor_payment_term_acct"
+ name="Vendor Payment Term"
+ action="vendor_payment_term_action"
+ parent="purchase.menu_purchase_products"
+ sequence="7"
+ />
+</odoo> \ No newline at end of file