diff options
| author | IT Fixcomart <it@fixcomart.co.id> | 2023-03-30 01:43:11 +0000 |
|---|---|---|
| committer | IT Fixcomart <it@fixcomart.co.id> | 2023-03-30 01:43:11 +0000 |
| commit | b5a9a4d37c07c32fb60753f29e7d982be221999b (patch) | |
| tree | 98668c355f6f5e832f368a1d0a373d7cae85b49d | |
| parent | 60d0b36cf33785c0cf6bea1d10b344dcdb37695a (diff) | |
| parent | 20eebfe836dcd6e971ccd0676b6294a2f3b06e5a (diff) | |
Merged in release (pull request #29)
Release
| -rwxr-xr-x | indoteknik_custom/__manifest__.py | 1 | ||||
| -rwxr-xr-x | indoteknik_custom/models/__init__.py | 2 | ||||
| -rw-r--r-- | indoteknik_custom/models/apache_solr.py | 70 | ||||
| -rw-r--r-- | indoteknik_custom/models/automatic_purchase.py | 149 | ||||
| -rw-r--r-- | indoteknik_custom/models/invoice_reklas.py | 21 | ||||
| -rw-r--r-- | indoteknik_custom/models/stock_move.py | 33 | ||||
| -rw-r--r-- | indoteknik_custom/models/stock_picking.py | 12 | ||||
| -rwxr-xr-x | indoteknik_custom/security/ir.model.access.csv | 6 | ||||
| -rw-r--r-- | indoteknik_custom/views/automatic_purchase.xml | 103 |
9 files changed, 384 insertions, 13 deletions
diff --git a/indoteknik_custom/__manifest__.py b/indoteknik_custom/__manifest__.py index 84a604d8..5873d73a 100755 --- a/indoteknik_custom/__manifest__.py +++ b/indoteknik_custom/__manifest__.py @@ -68,6 +68,7 @@ 'views/ip_lookup.xml', 'views/wati.xml', 'views/midtrans.xml', + 'views/automatic_purchase.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 7a4e445a..679004d1 100755 --- a/indoteknik_custom/models/__init__.py +++ b/indoteknik_custom/models/__init__.py @@ -56,3 +56,5 @@ from . import wati_api from . import wati_contact from . import uangmuka_penjualan from . import uangmuka_pembelian +from . import automatic_purchase +from . import apache_solr diff --git a/indoteknik_custom/models/apache_solr.py b/indoteknik_custom/models/apache_solr.py new file mode 100644 index 00000000..16cf5908 --- /dev/null +++ b/indoteknik_custom/models/apache_solr.py @@ -0,0 +1,70 @@ +from odoo import models, api, fields +from odoo.exceptions import UserError +from datetime import datetime +import logging +import pysolr + +_logger = logging.getLogger(__name__) + + +class ApacheSolr(models.Model): + _name = 'apache.solr' + _order = 'id desc' + + def _sync_product_to_solr(self): + _logger.info('run sync to solr...') + solr = pysolr.Solr('http://10.148.0.5:8983/solr/product/', timeout=100) + + templates = self.env['product.template'].search([ + ('solr_flag', '=', 0), + # ('id', '=', 21560) + ], limit=500) + document = [] + counter = 0 + for template in templates: + counter += 1 + price_excl_after_disc = price_excl = 0 + variants_name = variants_code = '' + if template.product_variant_count > 1: + for variant in template.product_variant_ids: + if price_excl_after_disc == 0: + price_excl = variant._get_website_price_exclude_tax() + price_excl_after_disc = variant._get_website_price_after_disc_and_tax() + elif variant._get_website_price_after_disc_and_tax() < price_excl_after_disc: + price_excl_after_disc = variant._get_website_price_after_disc_and_tax() + price_excl = variant._get_website_price_exclude_tax() + else: + price_excl_after_disc = price_excl_after_disc + price_excl = price_excl + variants_name += variant.display_name+', ' + variants_code += variant.default_code+', ' + + document=[({ + 'id': template.id, + 'display_name_s': template.display_name, + 'name_s': template.name, + 'default_code_s': template.default_code, + 'product_rating_i': template.product_rating, + 'product_id_i': template.id, + 'image_s': self.env['ir.attachment'].api_image('product.template', 'image_512', template.id), + 'price_f': price_excl or template.product_variant_id._get_website_price_exclude_tax(), + 'price_discount_f': price_excl_after_disc or template.product_variant_id._get_website_price_after_disc_and_tax(), + 'tax_f': template.product_variant_id._get_website_tax(), + 'variant_total_i': template.product_variant_count, + 'stock_total_i': template.qty_stock_vendor, + 'weight_f': template.weight, + 'manufacture_id_i': template.x_manufacture.id or 0, + 'image_promotion_1_s': self.env['ir.attachment'].api_image('x_manufactures', 'image_promotion_1', template.x_manufacture.id), + 'image_promotion_2_s': self.env['ir.attachment'].api_image('x_manufactures', 'image_promotion_2', template.x_manufacture.id), + 'category_id_i': template.categ_id.id or 0, + 'category_name_s': template.categ_id.name, + 'variants_name_t': variants_name, + 'variants_code_t': variants_code, + 'search_rank_i': template.search_rank, + 'search_rank_weekly_i': template.search_rank_weekly, + 'active_b': template.active + })] + solr.add(document) + # add counter for monitoring + _logger.info('%s / 500' % counter) + _logger.info('Success add to solr product %s' % template.id) diff --git a/indoteknik_custom/models/automatic_purchase.py b/indoteknik_custom/models/automatic_purchase.py new file mode 100644 index 00000000..e28f71f5 --- /dev/null +++ b/indoteknik_custom/models/automatic_purchase.py @@ -0,0 +1,149 @@ +from odoo import models, api, fields +from odoo.exceptions import UserError +from datetime import datetime +import logging + +_logger = logging.getLogger(__name__) + + +class AutomaticPurchase(models.Model): + _name = 'automatic.purchase' + _order = 'id desc' + + date_doc = fields.Date(string='Date', required=True, help='Isi tanggal hari ini') + description = fields.Char(string='Description', help='bebas isi nya apa') + purchase_lines = fields.One2many('automatic.purchase.line', 'automatic_purchase_id', string='Lines', auto_join=True) + notification = fields.Char(string='Notification') + is_po = fields.Boolean(string='Is PO') + purchase_match = fields.One2many('automatic.purchase.match', 'automatic_purchase_id', string='Matches', auto_join=True) + vendor_id = fields.Many2one('res.partner', string='Vendor', help='boleh kosong, jika diisi, maka hanya keluar data untuk vendor tersebut') + + def create_po_from_automatic_purchase(self): + if not self.purchase_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['automatic.purchase.line'].read_group([('automatic_purchase_id', '=', self.id), ('partner_id', '!=', False)], fields=['partner_id'], groupby=['partner_id']) + + for vendor in vendor_ids: + param_header = { + 'partner_id': vendor['partner_id'][0], + 'partner_ref': 'Automatic PO', + '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 + } + new_po = self.env['purchase.order'].create([param_header]) + products_vendors = self.env['automatic.purchase.line'].search([ + ('automatic_purchase_id', '=', self.id), + ('partner_id', '=', vendor['partner_id'][0]), + ('qty_purchase', '>', 0) + ]) + count=0 + for product in products_vendors: + count += 10 + param_line = { + 'order_id': new_po.id, + 'sequence': count, + 'product_id': product.product_id.id, + 'product_qty': product.qty_purchase, + 'product_uom_qty': product.qty_purchase, + 'price_unit': product.last_price, + } + new_line = self.env['purchase.order.line'].create([param_line]) + product.current_po_id = new_po.id + product.current_po_line_id = new_line.id + _logger.info('Automatic Create PO Line %s' % product.product_id.name) + self.notification = self.notification + ' %s' % new_po.name + self.env['automatic.purchase.match'].create([{ + 'automatic_purchase_id': self.id, + 'order_id': new_po.id + }]) + self.is_po = True + + def generate_automatic_purchase(self): + if self.purchase_lines: + raise UserError('Sudah digenerate sebelumnya, hapus line terlebih dahulu') + + query = [ + ('product_min_qty', '>', 0) + ] + orderpoints = self.env['stock.warehouse.orderpoint'].search(query) + count = 0 + for point in orderpoints: + # _logger.info('test %s' % point.product_id.name) + if point.product_id.qty_available > point.product_min_qty: + continue + qty_purchase = point.product_max_qty - point.product_id.qty_available + po_line = self.env['purchase.order.line'].search([('product_id', '=', point.product_id.id), ('order_id.state', '=', 'done')], limit=1) + + if self.vendor_id: + purchase_price = self.env['purchase.pricelist'].search([ + ('product_id', '=', point.product_id.id), + ('vendor_id', '=', self.vendor_id.id) + ], order='product_price asc', limit=1) + else: + purchase_price = self.env['purchase.pricelist'].search([('product_id', '=', point.product_id.id)], order='product_price asc', limit=1) + + vendor_id = purchase_price.vendor_id.id + price = purchase_price.product_price or 0 + + self.env['automatic.purchase.line'].create([{ + 'automatic_purchase_id': self.id, + 'product_id': point.product_id.id, + 'qty_purchase': qty_purchase, + 'qty_min': point.product_min_qty, + 'qty_max': point.product_max_qty, + 'qty_available': point.product_id.qty_available, + # 'partner_id': po_line.order_id.partner_id.id, + # 'last_price': po_line.price_unit, + 'partner_id': vendor_id, + 'last_price': price, + 'subtotal': qty_purchase * price, + 'last_order_id': po_line.order_id.id, + 'last_orderline_id': po_line.id, + 'brand_id': point.product_id.product_tmpl_id.x_manufacture.id + }]) + count += 1 + _logger.info('Create Automatic Purchase Line %s' % point.product_id.name) + self.notification = "Automatic PO Created %s Lines" % count + + +class AutomaticPurchaseLine(models.Model): + _name = 'automatic.purchase.line' + _description = 'Automatic Purchase Line' + _order = 'automatic_purchase_id, id' + + automatic_purchase_id = fields.Many2one('automatic.purchase', string='Ref', required=True, ondelete='cascade', index=True, copy=False) + product_id = fields.Many2one('product.product', string='Product') + qty_purchase = fields.Float(string='Qty Purchase') + qty_min = fields.Float(string='Qty Min') + qty_max = fields.Float(string='Qty Max') + qty_available = fields.Float(string='Qty Available') + partner_id = fields.Many2one('res.partner', string='Vendor') + last_price = fields.Float(string='Last Price') + subtotal = fields.Float(string='Subtotal') + last_order_id = fields.Many2one('purchase.order', string='Last Order') + last_orderline_id = fields.Many2one('purchase.order.line', string='Last Order Line') + 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') + brand_id = fields.Many2one('x_manufactures', string='Brand') + + +class AutomaticPurchaseMatch(models.Model): + _name = 'automatic.purchase.match' + _order = 'automatic_purchase_id, id' + + automatic_purchase_id = fields.Many2one('automatic.purchase', 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/indoteknik_custom/models/invoice_reklas.py b/indoteknik_custom/models/invoice_reklas.py index 70469b72..c2ee7e3d 100644 --- a/indoteknik_custom/models/invoice_reklas.py +++ b/indoteknik_custom/models/invoice_reklas.py @@ -26,16 +26,19 @@ class InvoiceReklas(models.TransientModel): invoices = self.env['account.move'].browse(self._context.get('active_ids', [])) current_time = datetime.now() for invoice in invoices: - + if self.reklas_type == 'penjualan': + ref_name = 'REKLAS '+self.reklas_id.name+" UANG MUKA PENJUALAN "+invoice.name+" "+invoice.partner_id.name + else: + ref_name = 'REKLAS '+self.reklas_id.name+" UANG MUKA PEMBELIAN "+invoice.name+" "+invoice.partner_id.name if self.reklas_type == 'penjualan': parameters_header = { - 'ref': 'REKLAS '+self.reklas_id.name+" UANG MUKA PENJUALAN "+invoice.name+" "+invoice.partner_id.name, + 'ref': ref_name, 'date': current_time, 'journal_id': 13 } else: parameters_header = { - 'ref': 'REKLAS ' + self.reklas_id.name + " UANG MUKA PEMBELIAN " + invoice.name + " " + invoice.partner_id.name, + 'ref': ref_name, 'date': current_time, 'journal_id': 13 } @@ -50,7 +53,8 @@ class InvoiceReklas(models.TransientModel): 'partner_id': invoice.partner_id.id, 'currency_id': 12, 'debit': self.pay_amt, - 'credit': 0 + 'credit': 0, + 'name': ref_name } parameter_credit = { 'move_id': account_move.id, @@ -58,7 +62,8 @@ class InvoiceReklas(models.TransientModel): 'partner_id': invoice.partner_id.id, 'currency_id': 12, 'debit': 0, - 'credit': self.pay_amt + 'credit': self.pay_amt, + 'name': ref_name } else: parameter_debit = { @@ -67,7 +72,8 @@ class InvoiceReklas(models.TransientModel): 'partner_id': invoice.partner_id.id, 'currency_id': 12, 'debit': self.pay_amt, - 'credit': 0 + 'credit': 0, + 'name': ref_name } parameter_credit = { 'move_id': account_move.id, @@ -75,7 +81,8 @@ class InvoiceReklas(models.TransientModel): 'partner_id': invoice.partner_id.id, 'currency_id': 12, 'debit': 0, - 'credit': self.pay_amt + 'credit': self.pay_amt, + 'name': ref_name } request.env['account.move.line'].create([parameter_debit, parameter_credit]) return { diff --git a/indoteknik_custom/models/stock_move.py b/indoteknik_custom/models/stock_move.py index 22a73010..bdbb0227 100644 --- a/indoteknik_custom/models/stock_move.py +++ b/indoteknik_custom/models/stock_move.py @@ -6,6 +6,39 @@ class StockMove(models.Model): line_no = fields.Integer('No', default=0) + def _prepare_account_move_line_from_mr(self, po_line, qty, move=False): + po_line.ensure_one() + aml_currency = move and move.currency_id or po_line.currency_id + date = move and move.date or fields.Date.today() + res = { + 'display_type': po_line.display_type, + 'sequence': po_line.sequence, + 'name': '%s: %s' % (po_line.order_id.name, po_line.name), + 'product_id': po_line.product_id.id, + 'product_uom_id': po_line.product_uom.id, + 'quantity': qty, + 'price_unit': po_line.currency_id._convert(po_line.price_unit, aml_currency, po_line.company_id, date, round=False), + 'tax_ids': [(6, 0, po_line.taxes_id.ids)], + 'analytic_account_id': po_line.account_analytic_id.id, + 'analytic_tag_ids': [(6, 0, po_line.analytic_tag_ids.ids)], + 'purchase_line_id': po_line.id, + } + if not move: + return res + + if self.currency_id == move.company_id.currency_id: + currency = False + else: + currency = move.currency_id + + res.update({ + 'move_id': move.id, + 'currency_id': currency and currency.id or False, + 'date_maturity': move.invoice_date_due, + 'partner_id': move.partner_id.id, + }) + return res + def _create_account_move_line(self, credit_account_id, debit_account_id, journal_id, qty, description, svl_id, cost): self.ensure_one() if self.picking_id.is_internal_use: diff --git a/indoteknik_custom/models/stock_picking.py b/indoteknik_custom/models/stock_picking.py index 77af676c..e63370f5 100644 --- a/indoteknik_custom/models/stock_picking.py +++ b/indoteknik_custom/models/stock_picking.py @@ -84,15 +84,17 @@ class StockPicking(models.Model): # Invoice values. invoice_vals = order._prepare_invoice() # Invoice line values (keep only necessary sections). - for line in order.order_line: - if line.display_type == 'line_section': + for line in self.move_ids_without_package: + po_line = self.env['purchase.order.line'].search([('order_id', '=', po.id), ('product_id', '=', line.product_id.id)], limit=1) + qty = line.product_uom_qty + if po_line.display_type == 'line_section': pending_section = line continue - if not float_is_zero(line.qty_to_invoice, precision_digits=precision): + if not float_is_zero(po_line.qty_to_invoice, precision_digits=precision): if pending_section: - invoice_vals['invoice_line_ids'].append((0, 0, pending_section._prepare_account_move_line())) + invoice_vals['invoice_line_ids'].append((0, 0, pending_section._prepare_account_move_line_from_mr(po_line, qty))) pending_section = None - invoice_vals['invoice_line_ids'].append((0, 0, line._prepare_account_move_line())) + invoice_vals['invoice_line_ids'].append((0, 0, line._prepare_account_move_line_from_mr(po_line, qty))) invoice_vals_list.append(invoice_vals) if not invoice_vals_list: diff --git a/indoteknik_custom/security/ir.model.access.csv b/indoteknik_custom/security/ir.model.access.csv index 65ab0a6c..1788c77f 100755 --- a/indoteknik_custom/security/ir.model.access.csv +++ b/indoteknik_custom/security/ir.model.access.csv @@ -40,4 +40,8 @@ access_wati_contact,access.wati.contact,model_wati_contact,,1,1,1,1 access_user_company_request,access.user.company.request,model_user_company_request,,1,1,1,1 access_res_partner_company_type,access.res.partner.company_type,model_res_partner_company_type,,1,1,1,1 access_uangmuka_penjualan,access.uangmuka.penjualan,model_uangmuka_penjualan,,1,1,1,1 -access_uangmuka_pembelian,access.uangmuka.pembelian,model_uangmuka_pembelian,,1,1,1,1
\ No newline at end of file +access_uangmuka_pembelian,access.uangmuka.pembelian,model_uangmuka_pembelian,,1,1,1,1 +access_automatic_purchase,access.automatic.purchase,model_automatic_purchase,,1,1,1,1 +access_automatic_purchase_line,access.automatic.purchase.line,model_automatic_purchase_line,,1,1,1,1 +access_automatic_purchase_match,access.automatic.purchase.match,model_automatic_purchase_match,,1,1,1,1 +access_apache_solr,access.apache.solr,model_apache_solr,,1,1,1,1
\ No newline at end of file diff --git a/indoteknik_custom/views/automatic_purchase.xml b/indoteknik_custom/views/automatic_purchase.xml new file mode 100644 index 00000000..49751f4e --- /dev/null +++ b/indoteknik_custom/views/automatic_purchase.xml @@ -0,0 +1,103 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<odoo> + <record id="automatic_purchase_tree" model="ir.ui.view"> + <field name="name">automatic.purchase.tree</field> + <field name="model">automatic.purchase</field> + <field name="arch" type="xml"> + <tree> + <field name="date_doc"/> + <field name="vendor_id"/> + <field name="description"/> + <field name="notification" readonly="1"/> + <field name="is_po" readonly="1"/> + </tree> + </field> + </record> + + <record id="automatic_purchase_line_tree" model="ir.ui.view"> + <field name="name">automatic.purchase.line.tree</field> + <field name="model">automatic.purchase.line</field> + <field name="arch" type="xml"> + <tree> + <field name="brand_id"/> + <field name="product_id"/> + <field name="qty_purchase"/> + <field name="qty_min"/> + <field name="qty_max"/> + <field name="qty_available"/> + <field name="partner_id"/> + <field name="last_price"/> + <field name="subtotal"/> + <field name="last_order_id" readonly="1"/> + <field name="current_po_line_id" readonly="1"/> + </tree> + </field> + </record> + + <record id="automatic_purchase_match_tree" model="ir.ui.view"> + <field name="name">automatic.purchase.match.tree</field> + <field name="model">automatic.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="automatic_purchase_form" model="ir.ui.view"> + <field name="name">automatic.purchase.form</field> + <field name="model">automatic.purchase</field> + <field name="arch" type="xml"> + <form> + <sheet string="Purchase"> + <div class="oe_button_box" name="button_box"/> + <group> + <group> + <field name="date_doc"/> + <field name="vendor_id"/> + <field name="description"/> + <field name="notification" readonly="1"/> + </group> + <group> + <div> + <button name="generate_automatic_purchase" + string="Generate Line" + type="object" + class="mr-2 oe_highlight" + /> + <button name="create_po_from_automatic_purchase" + string="Create PO" + type="object" + class="mr-2 oe_highlight" + /> + </div> + </group> + </group> + <notebook> + <page string="Lines"> + <field name="purchase_lines"/> + </page> + <page string="Matches"> + <field name="purchase_match"/> + </page> + </notebook> + </sheet> + </form> + </field> + </record> + + <record id="automatic_purchase_action" model="ir.actions.act_window"> + <field name="name">Automatic Purchase</field> + <field name="type">ir.actions.act_window</field> + <field name="res_model">automatic.purchase</field> + <field name="view_mode">tree,form</field> + </record> + + <menuitem id="menu_automatic_purchase" + name="Automatic Purchase" + action="automatic_purchase_action" + parent="menu_monitoring_in_purchase" + sequence="200"/> +</odoo>
\ No newline at end of file |
