summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xfixco_custom/__manifest__.py1
-rwxr-xr-xfixco_custom/models/__init__.py1
-rwxr-xr-xfixco_custom/models/product_product.py9
-rw-r--r--fixco_custom/models/purchase_order_line.py10
-rw-r--r--fixco_custom/models/requisition.py388
-rwxr-xr-xfixco_custom/security/ir.model.access.csv4
-rwxr-xr-xfixco_custom/views/product_product.xml4
-rw-r--r--fixco_custom/views/requisition.xml124
8 files changed, 22 insertions, 519 deletions
diff --git a/fixco_custom/__manifest__.py b/fixco_custom/__manifest__.py
index 5697dc2..44ec3be 100755
--- a/fixco_custom/__manifest__.py
+++ b/fixco_custom/__manifest__.py
@@ -32,7 +32,6 @@
'views/upload_ginee.xml',
'views/report_picking_list.xml',
'views/purchase_order.xml',
- 'views/requisition.xml',
'views/shipment_line.xml',
'views/manage_stock.xml',
'views/automatic_purchase.xml',
diff --git a/fixco_custom/models/__init__.py b/fixco_custom/models/__init__.py
index df56efb..150e15f 100755
--- a/fixco_custom/models/__init__.py
+++ b/fixco_custom/models/__init__.py
@@ -18,7 +18,6 @@ from . import uangmuka_penjualan
from . import upload_ginee
from . import purchase_order_line
from . import purchase_order
-from . import requisition
from . import account_move_line
from . import manage_stock
from . import automatic_purchase
diff --git a/fixco_custom/models/product_product.py b/fixco_custom/models/product_product.py
index a6bec4d..5117104 100755
--- a/fixco_custom/models/product_product.py
+++ b/fixco_custom/models/product_product.py
@@ -17,7 +17,16 @@ class ProductProduct(models.Model):
qty_pcs_box = fields.Float("Pcs Box")
barcode_box = fields.Char("Barcode Box")
qr_code_variant = fields.Binary("QR Code Variant", compute='_compute_qr_code_variant')
+ qty_multiple = fields.Float('Multiple')
+ def check_multiple_qty(self, other_qty):
+ if self.qty_multiple > 0 and other_qty > 0:
+ multiple = self.qty_multiple
+ if other_qty % multiple != 0:
+ return True
+ else:
+ return False
+
@api.constrains('name', 'default_code')
def constrains_product_type(self):
self.type = 'product'
diff --git a/fixco_custom/models/purchase_order_line.py b/fixco_custom/models/purchase_order_line.py
index eee5a7a..c06ed4f 100644
--- a/fixco_custom/models/purchase_order_line.py
+++ b/fixco_custom/models/purchase_order_line.py
@@ -1,4 +1,5 @@
-from odoo import models, fields, api
+from odoo import models, fields, api, _
+from odoo.exceptions import UserError
class PurchaseOrderLine(models.Model):
_inherit = 'purchase.order.line'
@@ -19,6 +20,13 @@ class PurchaseOrderLine(models.Model):
compute='_compute_discount_amount'
)
+ @api.constrains('product_qty', 'product_id')
+ def constrains_product_qty(self):
+ for line in self:
+ if line.product_id.check_multiple_qty(line.product_qty) == True:
+ raise UserError(f'Qty Product {line.product_id.display_name} tidak sesuai dengan kelipatan {line.product_id.qty_multiple}')
+
+
@api.depends('price_unit', 'product_qty', 'discount')
def _compute_discount_amount(self):
for line in self:
diff --git a/fixco_custom/models/requisition.py b/fixco_custom/models/requisition.py
deleted file mode 100644
index b0800ba..0000000
--- a/fixco_custom/models/requisition.py
+++ /dev/null
@@ -1,388 +0,0 @@
-from odoo import models, fields, api, tools, _
-from odoo.exceptions import UserError
-from datetime import datetime
-import math
-import logging
-
-_logger = logging.getLogger(__name__)
-
-
-class RequisitionMatchPO(models.Model):
- _name = 'v.requisition.match.po'
- _auto = False
- _rec_name = 'product_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'
- _inherit = ['mail.thread']
- _rec_name = 'number'
-
- number = fields.Char(string='Document No', index=True, copy=False, readonly=True)
- date_doc = fields.Date(string='Date', help='isi tanggal hari ini')
- description = fields.Char(string='Description', help='bebas isinya apa aja')
- requisition_lines = fields.One2many('requisition.line', 'requisition_id', string='Lines', auto_join=True)
- notification = fields.Char(string='Notification')
- is_po = fields.Boolean(string='Is PO')
- 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')
- sales_approve = fields.Boolean(string='Approval Status', tracking=3, copy=False)
- merchandise_approve = fields.Boolean(string='Approval Status', tracking=3, copy=False)
-
- def get_price(self, product):
- purchase_pricelist = self.env['purchase.pricelist'].search([
- ('product_id', '=', product)
- ], limit=1)
- if purchase_pricelist:
- return purchase_pricelist.price, purchase_pricelist.vendor_id.id
-
- def generate_requisition_from_so(self):
- state = ['done', 'sale']
- # if not self.sale_order_id:
- # raise UserError('Sale Order Wajib Diisi dan Harus Draft')
- # if self.sale_order_id.state in state:
- # raise UserError('SO sudah Confirm, akan berakibat double Purchase melalui PJ')
- # if not self.sale_order_id.order_line:
- # raise UserError('Line SO masih kosong, harus diisi dulu')
- for order_line in self.sale_order_id.order_line:
- price, vendor = self.get_price(order_line.product_id.id)
- param = {
- 'requisition_id': self.id,
- 'product_id': order_line.product_id.id,
- 'qty_purchase': order_line.product_uom_qty,
- 'partner_id': vendor,
- 'price_unit': price,
- 'taxes_id': 14,
- 'subtotal': price * order_line.product_uom_qty
- }
- self.env['requisition.line'].create([param])
-
- @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):
- state = ['done', 'sale']
- if self.sale_order_id.state in state:
- raise UserError('SO sudah Confirm, akan berakibat double Purchase melalui PJ')
- if self.env.user.id not in [21, 19, 28]:
- raise UserError('Hanya Rafly dan Darren Yang Bisa Approve')
- if self.env.user.id == 19 or self.env.user.id == 28:
- self.sales_approve = True
- elif self.env.user.id == 21 or self.env.user.id == 28:
- self.merchandise_approve = True
-
- def create_po_from_requisition(self):
- # if not self.sales_approve and not self.merchandise_approve:
- # raise UserError('Harus Di Approve oleh Darren atau Rafly')
- 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 not 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),
- ('partner_id', '!=', False)
- ], fields=['partner_id'], groupby=['partner_id'])
-
- po_ids = []
- for vendor in vendor_ids:
- result_po = self.create_po_by_vendor(vendor['partner_id'][0])
- po_ids += result_po
- return {
- 'name': _('Purchase Order'),
- 'view_mode': 'tree,form',
- 'res_model': 'purchase.order',
- 'target': 'current',
- 'type': 'ir.actions.act_window',
- 'domain': [('id', 'in', po_ids)],
- }
-
- def create_po_by_vendor(self, vendor_id):
- current_time = datetime.now()
-
- PRODUCT_PER_PO = 20
-
- requisition_line = self.env['requisition.line']
-
- param_header = {
- 'partner_id': vendor_id,
- # 'partner_ref': self.sale_order_id.name,
- 'currency_id': 12,
- 'user_id': self.env.user.id,
- 'company_id': 1, # indoteknik dotcom gemilang
- 'picking_type_id': 28, # indoteknik bandengan receipts
- 'date_order': current_time,
- 'sale_order_id': self.sale_order_id.id,
- # 'source': 'requisition',
- # 'note_description': 'from Purchase Requisition'
- }
-
- domain = [
- ('requisition_id', '=', self.id),
- ('partner_id', '=', vendor_id),
- ('qty_purchase', '>', 0)
- ]
-
- products_len = requisition_line.search_count(domain)
- page = math.ceil(products_len / PRODUCT_PER_PO)
- po_ids = []
- # i start from zero (0)
- for i in range(page):
- new_po = self.env['purchase.order'].create([param_header])
- new_po.source = 'requisition'
- po_ids.append(new_po.id)
- lines = requisition_line.search(
- domain,
- offset=i * PRODUCT_PER_PO,
- limit=PRODUCT_PER_PO
- )
- tax = [22]
-
- for line in lines:
- product = line.product_id
- param_line = {
- 'order_id' : new_po.id,
- 'product_id': product.id,
- 'product_qty': line.qty_purchase,
- 'product_uom_qty': line.qty_purchase,
- 'name': product.display_name,
- 'price_unit': line.price_unit,
- 'taxes_id': tax,
- }
- 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):
- # 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')
- # current_time = datetime.now()
- # vendor_ids = self.env['requisition.line'].read_group([('requisition_id', '=', self.id), ('partner_id', '!=', False)], fields=['partner_id'], groupby=['partner_id'])
-
- # counter_po_number = 0
- # po_ids = []
- # for vendor in vendor_ids:
- # param_header = {
- # 'partner_id': vendor['partner_id'][0],
- # # 'partner_ref': self.sale_order_id.name,
- # 'currency_id': 12,
- # 'user_id': self.env.user.id,
- # 'company_id': 1, # indoteknik dotcom gemilang
- # 'picking_type_id': 28, # indoteknik bandengan receipts
- # 'date_order': current_time,
- # 'sale_order_id': self.sale_order_id.id,
- # 'note_description': 'from Purchase Requisition'
- # }
- # param_requisition_line = [
- # ('requisition_id', '=', self.id),
- # ('partner_id', '=', vendor['partner_id'][0]),
- # ('qty_purchase', '>', 0)
- # ]
- # # new_po = self.env['purchase.order'].create([param_header])
- # products_vendors = self.env['requisition.line'].search(, order='brand_id')
- # count = brand_id = 0
-
- # for product in products_vendors:
- # if count > 200 or brand_id != product.brand_id.id:
- # continue
-
- # count = 0
- # counter_po_number += 1
- # new_po = self.env['purchase.order'].create([param_header])
- # new_po.name = new_po.name + "/R/"+str(counter_po_number)
- # self.env['requisition.purchase.match'].create([{
- # 'requisition_id': self.id,
- # 'order_id': new_po.id
- # }])
- # po_ids.append(new_po.id)
- # self.env.cr.commit()
- # # else:
- # # new_po = self.env['purchase.order'].create([param_header])
- # brand_id = product.brand_id.id
- # count += 10
-
- # # qty_available = product.product_id.qty_onhand_bandengan + product.product_id.qty_incoming_bandengan - product.product_id.outgoing_qty
- # # suggest = 'harus beli'
- # # if qty_available > product.qty_purchase:
- # # suggest = 'masih cukup'
-
- # tax = [22]
-
- # param_line = {
-
- # 'sequence': count,
- # 'product_id': product.product_id.id,
- # 'product_qty': product.qty_purchase,
- # 'product_uom_qty': product.qty_purchase,
- # 'price_unit': product.price_unit,
- # 'taxes_id': tax,
- # # 'qty_available_store': qty_available,
- # # 'suggest': suggest,
- # }
- # new_line = self.env['purchase.order.line'].create([param_line])
- # if new_po:
- # new_line.write({
- # 'order_id': new_po.id,
- # })
- # product.current_po_id = new_po.id
- # product.current_po_line_id = new_line.id
- # _logger.info('Create PO Line %s' % product.product_id.name)
- # # self.notification = self.notification + ' %s' % new_po.name
- # self.is_po = True
- # if po_ids:
- # return {
- # 'name': _('Purchase Order'),
- # 'view_mode': 'tree,form',
- # 'res_model': 'purchase.order',
- # 'target': 'current',
- # 'type': 'ir.actions.act_window',
- # 'domain': [('id', 'in', po_ids)],
- # }
-
-class RequisitionLine(models.Model):
- _name = 'requisition.line'
- _description = 'Requisition Line'
- _order = 'requisition_id, id'
- _inherit = ['mail.thread']
-
- requisition_id = fields.Many2one('requisition', string='Ref', required=True, ondelete='cascade', index=True, copy=False)
- product_id = fields.Many2one('product.product', string='Product', tracking=3,)
- partner_id = fields.Many2one('res.partner', string='Vendor')
- qty_purchase = fields.Float(string='Qty Purchase')
- price_unit = fields.Float(string='Price')
- tax_id = fields.Many2one('account.tax', help='isi tax pembelian include atau exclude', domain="[('type_tax_use', '=', 'purchase')]")
- subtotal = fields.Float(string='Subtotal')
- last_price = fields.Float(string='Last Price')
- last_order_id = fields.Many2one('purchase.order', string='Last Order')
- last_orderline_id = fields.Many2one('purchase.order.line', string='Last Order Line')
- taxes_id = fields.Many2one('account.tax', string='Tax')
- is_po = fields.Boolean(String='Is PO')
- current_po_id = fields.Many2one('purchase.order', string='Current')
- current_po_line_id = fields.Many2one('purchase.order.line', string='Current Line')
- source = fields.Char(string='Source', help='data harga diambil darimana')
- qty_available_store = fields.Float(string='Available')
- suggest = fields.Char(string='Suggest')
-
- def _get_valid_purchase_price(self, purchase_price):
- price = 0
- taxes = 24
- 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':
- price = purchase_price.product_price
- taxes = purchase_price.taxes_product_id.id or 24
-
- 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 or 24
-
- return price, taxes
-
- @api.onchange('price_unit')
- def _onchange_price_unit(self):
- for line in self:
- line.subtotal = line.price_unit * line.qty_purchase
-
- @api.onchange('product_id')
- def _onchange_product(self):
- for line in self:
- purchase_pricelist = self.env['purchase.pricelist'].search([
- ('product_id', '=', line.product_id.id)
- ], limit=1)
-
- # price, taxes = line._get_valid_purchase_price(purchase_pricelist)
- line.price_unit = purchase_pricelist.price
- line.partner_id = purchase_pricelist.vendor_id.id
-
- @api.model
- def create(self, vals):
- record = super(RequisitionLine, self).create(vals)
- record._track_changes('Tambah')
- return record
-
- def write(self, vals):
- for record in self:
- old_values = {field: record[field] for field in vals if field in record}
-
- result = super(RequisitionLine, self).write(vals)
-
- for record in self:
- record._track_changes('Updated', old_values)
-
- return result
-
- def unlink(self):
- for record in self:
- record._track_changes('Hapus')
- return super(RequisitionLine, self).unlink()
-
- def _track_changes(self, action, old_values=None):
- message = f"Produk telah di-{action} : <br/>"
- if action == 'Tambah':
- # message += f"<br/> Product: {self.product_id.name}"
- message += f"Product: {self.product_id.name} <br/> Vendor: {self.partner_id.name} <br/> Qty: {self.qty_purchase} <br/> Price: {self.price_unit} <br/> Tax: {self.tax_id.name} <br/> Subtotal: {self.subtotal} <br/>"
- elif action == 'Hapus':
- # message += f"<br/> Deleted Product: {self.product_id.name}"
- message += f"<br/> Deleted Product: {self.product_id.name} <br/> Vendor: {self.partner_id.name} Qty: {self.qty_purchase} <br/> Price: {self.price_unit} <br/> Tax: {self.tax_id.name} <br/> Subtotal: {self.subtotal} <br/>"
- else: # Updated
- for field, old_value in old_values.items():
- new_value = self[field]
- if old_value != new_value:
- field_label = self._fields[field].string # Ambil nama label field
- message += f"{field_label}: {old_value} -> {new_value}<br/>"
-
- if self.requisition_id:
- self.requisition_id.message_post(body=message)
-
-class RequisitionPurchaseMatch(models.Model):
- _name = 'requisition.purchase.match'
- _order = 'requisition_id, id'
-
- requisition_id = fields.Many2one('requisition', string='Ref', required=True, ondelete='cascade', index=True, copy=False)
- order_id = fields.Many2one('purchase.order', string='Purchase Order')
- vendor = fields.Char(string='Vendor', compute='_compute_info_po')
- total = fields.Float(string='Total', compute='_compute_info_po')
-
- def _compute_info_po(self):
- for match in self:
- match.vendor = match.order_id.partner_id.name
- match.total = match.order_id.amount_total
diff --git a/fixco_custom/security/ir.model.access.csv b/fixco_custom/security/ir.model.access.csv
index 4f20dfe..cdfaa49 100755
--- a/fixco_custom/security/ir.model.access.csv
+++ b/fixco_custom/security/ir.model.access.csv
@@ -22,10 +22,6 @@ access_uangmuka_penjualan,access.uangmuka.penjualan,model_uangmuka_penjualan,,1,
access_picking_line,access.picking.line,model_picking_line,,1,1,1,1
access_upload_ginee,access.upload.ginee,model_upload_ginee,,1,1,1,1
access_upload_ginee_line,access.upload.ginee.line,model_upload_ginee_line,,1,1,1,1
-access_requisition,access.requisition,model_requisition,,1,1,1,1
-access_requisition_line,access.requisition.line,model_requisition_line,,1,1,1,1
-access_requisition_purchase_match,access.requisition.purchase.match,model_requisition_purchase_match,,1,1,1,1
-access_v_requisition_match_po,access.v.requisition.match.po,model_v_requisition_match_po,,1,1,1,1
access_product_shipment_line,access.product.shipment.line,model_product_shipment_line,,1,1,1,1
access_manage_stock,access.manage.stock,model_manage_stock,,1,1,1,1
access_automatic_purchase_line,access.automatic.purchase.line,model_automatic_purchase_line,,1,1,1,1
diff --git a/fixco_custom/views/product_product.xml b/fixco_custom/views/product_product.xml
index 7842909..6c468ba 100755
--- a/fixco_custom/views/product_product.xml
+++ b/fixco_custom/views/product_product.xml
@@ -7,10 +7,14 @@
<field name="inherit_id" ref="product.product_normal_form_view"/>
<field name="arch" type="xml">
<field name="categ_id" position="after">
+ <field name="qty_multiple" />
<field name="barcode_box" />
<field name="qty_pcs_box" />
<field name="qr_code_variant" widget="image" readonly="True"/>
</field>
+ <field name="uom_po_id" position="after">
+ <field name="qty_multiple" />
+ </field>
<notebook position="inside">
<page string="Bundling">
<field name="bundling_line_ids"/>
diff --git a/fixco_custom/views/requisition.xml b/fixco_custom/views/requisition.xml
deleted file mode 100644
index 3648401..0000000
--- a/fixco_custom/views/requisition.xml
+++ /dev/null
@@ -1,124 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-<odoo>
- <record id="requisition_tree" model="ir.ui.view">
- <field name="name">requisition.tree</field>
- <field name="model">requisition</field>
- <field name="arch" type="xml">
- <tree>
- <field name="date_doc"/>
- <field name="number"/>
- <field name="description"/>
- <field name="notification" readonly="1"/>
- <field name="is_po" readonly="1"/>
- </tree>
- </field>
- </record>
-
- <record id="requisition_line_tree" model="ir.ui.view">
- <field name="name">requisition.line.tree</field>
- <field name="model">requisition.line</field>
- <field name="arch" type="xml">
- <tree>
- <field name="product_id"/>
- <field name="partner_id"/>
- <field name="qty_purchase"/>
- <field name="price_unit"/>
- <field name="tax_id"/>
- <field name="subtotal"/>
- <field name="source"/>
- <field name="qty_available_store"/>
- <field name="suggest"/>
- </tree>
- </field>
- </record>
-
- <record id="requisition_purchase_match_tree" model="ir.ui.view">
- <field name="name">requisition.purchase.match.tree</field>
- <field name="model">requisition.purchase.match</field>
- <field name="arch" type="xml">
- <tree>
- <field name="order_id" readonly="1"/>
- <field name="vendor" readonly="1"/>
- <field name="total" readonly="1"/>
- </tree>
- </field>
- </record>
-
- <record id="requisition_form" model="ir.ui.view">
- <field name="name">requisition.form</field>
- <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>
- <group>
- <field name="number"/>
- <field name="date_doc"/>
- <field name="sale_order_id"/>
- <field name="description"/>
- <field name="notification" readonly="1"/>
- </group>
- <group>
- <div>
- <button name="generate_requisition_from_so"
- string="Create Line from SO"
- type="object"
- class="mr-2 oe_highlight"
- />
- </div>
- <div>
- <button name="create_po_from_requisition"
- string="Create PO"
- type="object"
- class="mr-2 oe_highlight"
- />
- </div>
- </group>
- </group>
- <notebook>
- <page string="Lines">
- <field name="requisition_lines">
- <tree editable="line">
- <field name="product_id" required="1"/>
- <field name="partner_id" required="1" />
- <field name="qty_purchase" required="1" />
- <field name="price_unit" required="1" />
- <field name="taxes_id" readonly="1" />
- <field name="subtotal" readonly="1" />
- </tree>
- </field>
- </page>
- <page string="Matches">
- <field name="requisition_match"/>
- </page>
- </notebook>
- </sheet>
- <div class="oe_chatter">
- <field name="message_follower_ids" widget="mail_followers"/>
- <field name="message_ids" widget="mail_thread"/>
- </div>
- </form>
- </field>
- </record>
-
- <record id="requisition_action" model="ir.actions.act_window">
- <field name="name">Requisition</field>
- <field name="type">ir.actions.act_window</field>
- <field name="res_model">requisition</field>
- <field name="view_mode">tree,form</field>
- </record>
-
- <menuitem id="menu_requisition"
- name="Requisition"
- action="requisition_action"
- parent="purchase.menu_procurement_management"
- sequence="300"/>
-</odoo> \ No newline at end of file