summaryrefslogtreecommitdiff
path: root/fixco_custom/models
diff options
context:
space:
mode:
Diffstat (limited to 'fixco_custom/models')
-rwxr-xr-xfixco_custom/models/__init__.py1
-rw-r--r--fixco_custom/models/automatic_purchase.py106
-rw-r--r--fixco_custom/models/manage_stock.py75
-rw-r--r--fixco_custom/models/purchase_pricelist.py4
-rw-r--r--fixco_custom/models/purchasing_job.py113
5 files changed, 291 insertions, 8 deletions
diff --git a/fixco_custom/models/__init__.py b/fixco_custom/models/__init__.py
index 150e15f..27178c6 100755
--- a/fixco_custom/models/__init__.py
+++ b/fixco_custom/models/__init__.py
@@ -21,3 +21,4 @@ from . import purchase_order
from . import account_move_line
from . import manage_stock
from . import automatic_purchase
+from . import purchasing_job
diff --git a/fixco_custom/models/automatic_purchase.py b/fixco_custom/models/automatic_purchase.py
index 7612f4a..f3f650d 100644
--- a/fixco_custom/models/automatic_purchase.py
+++ b/fixco_custom/models/automatic_purchase.py
@@ -19,8 +19,9 @@ class AutomaticPurchase(models.Model):
is_po = fields.Boolean(string='Is PO', tracking=True)
responsible_id = fields.Many2one('res.users', string='Responsible', tracking=True, default=lambda self: self.env.user)
apo_type = fields.Selection([
- ('regular', 'Regular Fulfill SO'),
+ ('purchasing_job', 'Purchasing Job'),
('reordering', 'Reordering Rule'),
+ ('requisition', 'Requisition'),
], string='Type', tracking=True)
purchase_order_ids = fields.One2many(
'purchase.order',
@@ -31,6 +32,55 @@ class AutomaticPurchase(models.Model):
string='Purchase Orders',
compute='_compute_purchase_order_count'
)
+ sale_order_id = fields.Many2one('sale.order', string='Sales Order')
+
+ def action_generate_lines_from_so(self):
+ self.ensure_one()
+
+ self.automatic_purchase_lines.unlink()
+
+ if not self.sale_order_id:
+ raise UserError("Please select a Sales Order first.")
+
+ lines = []
+
+ for line in self.sale_order_id.order_line:
+ product = line.product_id
+
+ manage_stock = self.env['manage.stock'].search([
+ ('product_id', '=', product.id)
+ ], limit=1)
+
+ qty_min = manage_stock.min_stock if manage_stock else 0.0
+ qty_buffer = manage_stock.buffer_stock if manage_stock else 0.0
+
+ quant = self.env['stock.quant'].search([
+ ('product_id', '=', product.id)
+ ], limit=1)
+ qty_available = quant.available_quantity if quant else 0.0
+
+ pricelist = self.env['purchase.pricelist'].search([
+ ('product_id', '=', product.id)
+ ], limit=1)
+
+ vendor = pricelist.vendor_id if pricelist else False
+ price = pricelist.price if pricelist else 0.0
+ subtotal = price * line.product_uom_qty
+
+ lines.append({
+ 'automatic_purchase_id': self.id,
+ 'product_id': product.id,
+ 'qty_purchase': line.product_uom_qty,
+ 'qty_min': qty_min,
+ 'qty_buffer': qty_buffer,
+ 'qty_available': qty_available,
+ 'partner_id': vendor.id if vendor else False,
+ 'taxes_id': vendor.tax_id.id if vendor else False,
+ 'price': price,
+ 'subtotal': subtotal,
+ })
+
+ self.env['automatic.purchase.line'].create(lines)
def action_view_related_po(self):
self.ensure_one()
@@ -77,7 +127,7 @@ class AutomaticPurchase(models.Model):
for vendor_id, lines in vendor_lines.items():
vendor = self.env['res.partner'].browse(vendor_id)
- chunk_size = 20
+ chunk_size = 10
line_chunks = [lines[i:i + chunk_size] for i in range(0, len(lines), chunk_size)]
for index, chunk in enumerate(line_chunks):
@@ -105,7 +155,7 @@ class AutomaticPurchase(models.Model):
'company_id': self.env.company.id,
'currency_id': vendor.property_purchase_currency_id.id or self.env.company.currency_id.id,
'automatic_purchase_id': self.id,
- 'source': 'reordering',
+ 'source': self.apo_type,
})
def _create_purchase_order_line(self, order, line):
@@ -141,7 +191,7 @@ class AutomaticPurchase(models.Model):
])
# Hitung total qty_available (quantity - reserved_quantity) untuk lokasi tersebut
- total_available = quant_records.available_quantity or 0.0
+ total_available = quant_records.quantity or 0.0
# Log nilai untuk debugging
_logger.info(
@@ -195,7 +245,6 @@ class AutomaticPurchase(models.Model):
'qty_purchase': qty_purchase,
'qty_min': stock.min_stock,
'qty_buffer': stock.buffer_stock,
- 'qty_available': total_available,
'partner_id': stock.vendor_id.id,
'taxes_id': stock.vendor_id.tax_id.id,
'price': price,
@@ -235,7 +284,10 @@ class AutomaticPurchaseLine(models.Model):
qty_purchase = fields.Float(string='Qty Purchase')
qty_min = fields.Float(string='Qty Min')
qty_buffer = fields.Float(string='Qty Buffer')
- qty_available = fields.Float(string='Qty Available')
+ qty_available = fields.Float(string='Qty Available', compute='compute_qty_available')
+ qty_onhand = fields.Float(string='Qty On Hand', compute='compute_qty_onhand')
+ qty_incoming = fields.Float(string='Qty Incoming', compute='compute_qty_incoming')
+ qty_outgoing = fields.Float(string='Qty Outgoing', compute='compute_qty_outgoing')
partner_id = fields.Many2one('res.partner', string='Vendor')
price = fields.Float(string='Price')
subtotal = fields.Float(string='Subtotal')
@@ -244,4 +296,44 @@ class AutomaticPurchaseLine(models.Model):
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')
- taxes_id = fields.Many2one('account.tax', string='Taxes') \ No newline at end of file
+ taxes_id = fields.Many2one('account.tax', string='Taxes')
+
+ def compute_qty_available(self):
+ for line in self:
+ if line.product_id:
+ stock_quant = self.env['stock.quant'].search([
+ ('product_id', '=', line.product_id.id),
+ ('location_id', '=', 55)
+ ], limit=1)
+ line.qty_available = stock_quant.available_quantity if stock_quant else 0.0
+
+ def compute_qty_onhand(self):
+ for line in self:
+ if line.product_id:
+ stock_quant = self.env['stock.quant'].search([
+ ('product_id', '=', line.product_id.id),
+ ('location_id', '=', 55)
+ ], limit=1)
+ line.qty_onhand = stock_quant.quantity if stock_quant else 0.0
+
+ def compute_qty_incoming(self):
+ for line in self:
+ if line.product_id:
+ stock_move = self.env['stock.move'].search([
+ ('product_id', '=', line.product_id.id),
+ ('location_dest_id', '=', 55),
+ ('location_id', '=', 4),
+ ('state', 'in', ['waiting', 'confirmed', 'assigned', 'partially_available'])
+ ])
+ line.qty_incoming = sum(move.product_uom_qty for move in stock_move)
+
+ def compute_qty_outgoing(self):
+ for line in self:
+ if line.product_id:
+ stock_move = self.env['stock.move'].search([
+ ('product_id', '=', line.product_id.id),
+ ('location_dest_id', '=', 5),
+ ('location_id', '=', 55),
+ ('state', 'in', ['waiting', 'confirmed', 'assigned', 'partially_available'])
+ ], limit=1)
+ line.qty_outgoing = sum(move.product_uom_qty for move in stock_move) \ No newline at end of file
diff --git a/fixco_custom/models/manage_stock.py b/fixco_custom/models/manage_stock.py
index 4375ad2..e654b4e 100644
--- a/fixco_custom/models/manage_stock.py
+++ b/fixco_custom/models/manage_stock.py
@@ -15,7 +15,80 @@ class ManageStock(models.Model):
min_stock = fields.Float(string='Min Stock', required=True)
buffer_stock = fields.Float(string='Buffer Stock', required=True)
vendor_id = fields.Many2one('res.partner', string="Vendor", required=True)
+ qty_available = fields.Float(string='Qty Available', compute='_compute_qty_available')
+ qty_onhand = fields.Float(string='Qty Onhand', compute='_compute_qty_available')
_sql_constraints = [
('product_unique', 'unique (product_id)', 'This product already has a stock management rule!'),
- ] \ No newline at end of file
+ ]
+
+ def _compute_qty_available(self):
+ for record in self:
+ quant_records = self.env['stock.quant'].search([
+ ('product_id', '=', record.product_id.id),
+ # ('id','in', [80,81]),
+ ('location_id', '=', 55)
+ ])
+
+ total_available = quant_records.available_quantity or 0.0
+ total_onhand = quant_records.quantity or 0.0
+ record.qty_available = total_available
+ record.qty_onhand = total_onhand
+
+ def create_automatic_purchase(self):
+ if not self:
+ raise UserError("No stock records selected.")
+
+ automatic_purchase = self.env['automatic.purchase'].create({
+ 'apo_type': 'reordering',
+ })
+
+ lines_to_create = []
+
+ for stock in self:
+ location_id = 55
+
+ quant_records = self.env['stock.quant'].search([
+ ('product_id', '=', stock.product_id.id),
+ ('location_id', '=', location_id)
+ ])
+
+ total_available = quant_records.quantity or 0.0
+
+ qty_incoming = stock.product_id.incoming_qty or 0.0
+
+ qty_purchase = stock.buffer_stock - (total_available + qty_incoming)
+
+ qty_purchase = max(qty_purchase, 0.0)
+
+ pricelist = self.env['purchase.pricelist'].search([
+ ('product_id', '=', stock.product_id.id),
+ ('vendor_id', '=', stock.vendor_id.id)
+ ], limit=1)
+
+ price = pricelist.price if pricelist else 0.0
+ subtotal = qty_purchase * price
+
+ lines_to_create.append({
+ 'automatic_purchase_id': automatic_purchase.id,
+ 'product_id': stock.product_id.id,
+ 'qty_purchase': qty_purchase,
+ 'qty_min': stock.min_stock,
+ 'qty_buffer': stock.buffer_stock,
+ 'partner_id': stock.vendor_id.id,
+ 'taxes_id': stock.vendor_id.tax_id.id if stock.vendor_id.tax_id else False,
+ 'price': price,
+ 'subtotal': subtotal,
+ })
+
+ self.env['automatic.purchase.line'].create(lines_to_create)
+
+ return {
+ 'type': 'ir.actions.act_window',
+ 'res_model': 'automatic.purchase',
+ 'view_mode': 'form',
+ 'res_id': automatic_purchase.id,
+ 'target': 'current',
+ }
+
+
diff --git a/fixco_custom/models/purchase_pricelist.py b/fixco_custom/models/purchase_pricelist.py
index 2d0a77c..6f5bd21 100644
--- a/fixco_custom/models/purchase_pricelist.py
+++ b/fixco_custom/models/purchase_pricelist.py
@@ -13,6 +13,10 @@ class PurchasePricelist(models.Model):
vendor_id = fields.Many2one('res.partner', string="Vendor", required=True)
price = fields.Float(string='Price', required=True)
+ _sql_constraints = [
+ ('product_unique', 'unique (product_id)', 'This product already has a purchase pricelist!'),
+ ]
+
@api.depends('product_id', 'vendor_id')
def _compute_name(self):
self.name = self.vendor_id.name + ', ' + self.product_id.name \ No newline at end of file
diff --git a/fixco_custom/models/purchasing_job.py b/fixco_custom/models/purchasing_job.py
new file mode 100644
index 0000000..4f301f9
--- /dev/null
+++ b/fixco_custom/models/purchasing_job.py
@@ -0,0 +1,113 @@
+from odoo import models, fields, tools
+from odoo.exceptions import AccessError, UserError, ValidationError
+from datetime import timedelta, date
+
+class PurchasingJob(models.Model):
+ _name = 'purchasing.job'
+ _description = 'Procurement Monitoring by Product'
+ _auto = False
+ _rec_name = 'product'
+
+ id = fields.Integer(string='ID', readonly=True)
+ item_code = fields.Char(string='Item Code')
+ product = fields.Char(string='Product')
+ onhand = fields.Float(string='On Hand')
+ incoming = fields.Float(string='Incoming')
+ outgoing = fields.Float(string='Outgoing')
+ action = fields.Char(string='Action')
+ product_id = fields.Many2one('product.product', string='Product')
+ vendor_id = fields.Many2one('res.partner', string='Vendor')
+
+ def create_automatic_purchase(self):
+ if not self:
+ raise UserError("No Purchasing Job selected.")
+
+ automatic_purchase = self.env['automatic.purchase'].create({
+ 'apo_type': 'purchasing_job',
+ })
+
+ lines_to_create = []
+
+ for stock in self:
+ manage_stock = self.env['manage.stock'].search([
+ ('product_id', '=', stock.product_id.id)
+ ], limit=1)
+
+ qty_purchase = stock.outgoing - (stock.onhand + stock.incoming)
+
+ qty_purchase = max(qty_purchase, 0.0)
+
+ pricelist = self.env['purchase.pricelist'].search([
+ ('product_id', '=', stock.product_id.id),
+ ('vendor_id', '=', stock.vendor_id.id)
+ ], limit=1)
+
+ price = pricelist.price if pricelist else 0.0
+ subtotal = qty_purchase * price
+
+ lines_to_create.append({
+ 'automatic_purchase_id': automatic_purchase.id,
+ 'product_id': stock.product_id.id,
+ 'qty_purchase': qty_purchase,
+ 'qty_min': manage_stock.min_stock,
+ 'qty_buffer': manage_stock.buffer_stock,
+ 'partner_id': stock.vendor_id.id,
+ 'taxes_id': stock.vendor_id.tax_id.id if stock.vendor_id.tax_id else False,
+ 'price': price,
+ 'subtotal': subtotal,
+ })
+
+ self.env['automatic.purchase.line'].create(lines_to_create)
+
+ return {
+ 'type': 'ir.actions.act_window',
+ 'res_model': 'automatic.purchase',
+ 'view_mode': 'form',
+ 'res_id': automatic_purchase.id,
+ 'target': 'current',
+ }
+
+ def init(self):
+ tools.drop_view_if_exists(self.env.cr, self._table)
+ self.env.cr.execute("""
+ CREATE OR REPLACE VIEW %s AS
+ SELECT
+ row_number() OVER () AS id,
+ a.item_code,
+ a.product,
+ a.onhand,
+ a.incoming,
+ a.outgoing,
+ CASE
+ WHEN (a.incoming + a.onhand) < a.outgoing THEN 'kurang'
+ ELSE 'cukup'
+ END AS action,
+ a.product_id,
+ pp2.vendor_id
+ FROM (
+ SELECT
+ COALESCE(pp.default_code, pt.default_code) AS item_code,
+ pt.name AS product,
+ get_qty_onhand(pp.id::numeric) AS onhand,
+ get_qty_incoming(pp.id::numeric) AS incoming,
+ get_qty_outgoing(pp.id::numeric) AS outgoing,
+ pp.id AS product_id
+ FROM stock_move sm
+ JOIN stock_picking sp ON sp.id = sm.picking_id
+ JOIN product_product pp ON pp.id = sm.product_id
+ JOIN product_template pt ON pt.id = pp.product_tmpl_id
+ WHERE sp.state IN ('draft', 'waiting', 'confirmed', 'assigned')
+ AND sp.name LIKE '%%OUT%%'
+ AND sm.location_id = 55
+ GROUP BY pp.id, pp.default_code, pt.default_code, pt.name
+ ) a
+ LEFT JOIN LATERAL (
+ SELECT vendor_id
+ FROM purchase_pricelist
+ WHERE product_id = a.product_id
+ ORDER BY id ASC
+ LIMIT 1
+ ) pp2 ON true
+ """ % self._table)
+
+