diff options
| author | it-fixcomart <it@fixcomart.co.id> | 2024-08-14 16:12:14 +0700 |
|---|---|---|
| committer | it-fixcomart <it@fixcomart.co.id> | 2024-08-14 16:12:14 +0700 |
| commit | d47eb069978ce67bce1a19b6c824a53ca3d68801 (patch) | |
| tree | 2427f680d68c8b136531d392eb36cf4262c7d35b | |
| parent | 2513b765773fca587dbd298e77732d2d005949c8 (diff) | |
| parent | d4df708e5195e1c0c3b8e0ad90b7518e5d4d48c2 (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.
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 |
