diff options
| author | Azka Nathan <darizkyfaz@gmail.com> | 2024-07-02 10:06:29 +0700 |
|---|---|---|
| committer | Azka Nathan <darizkyfaz@gmail.com> | 2024-07-02 10:06:29 +0700 |
| commit | a10024fec206f68791c87a5a4e56e4c6bce28f5c (patch) | |
| tree | 627d0ca2443eecbcb44b1b4eeda98f94c9ea3496 | |
| parent | 51c19eca13239fe20ae592f8e9ee0d23f8904c5f (diff) | |
| parent | f9c5b3dffcd71bfa9dea74c946d7b4277db66bd6 (diff) | |
Merge branch 'production' into feature/add_voucher_pastihemat_productsolr
33 files changed, 1006 insertions, 204 deletions
diff --git a/indoteknik_api/controllers/api_v1/partner.py b/indoteknik_api/controllers/api_v1/partner.py index e61c98c1..a6e14a19 100644 --- a/indoteknik_api/controllers/api_v1/partner.py +++ b/indoteknik_api/controllers/api_v1/partner.py @@ -7,6 +7,42 @@ class Partner(controller.Controller): _name = 'res.partner' prefix = '/api/v1/' + def get_partner_child_ids(self, partner_id): + partner = request.env[self._name].search([('id', '=', partner_id)], limit=1) + if not partner.parent_id: + partner_child_ids = [x['id'] for x in partner.child_ids] + [partner.id] + if partner.parent_id: + partner_child_ids = [x['id'] for x in partner.parent_id.child_ids] + return partner_child_ids + + @http.route(prefix + 'partner/<id>/list/site', auth='public', methods=['GET', 'OPTIONS']) + @controller.Controller.must_authorized() + def get_list_partner_by_id(self, **kw): + params = self.get_request_params(kw, { + 'id': ['required', 'number'] + }) + + if not params['valid']: + return self.response(code=400, description=params) + + partner_id = params['value']['id'] + + partner_child_ids = self.get_partner_child_ids(partner_id) + + partners = request.env['res.partner'].search([('id', 'in', partner_child_ids)]) + + site_names = set() + for partner in partners: + if partner.site_id: + site_names.add(partner.site_id.name) + + data = { + 'sites': list(site_names) + } + + return self.response(data) + + @http.route(prefix + 'partner/<id>/address', auth='public', methods=['GET', 'OPTIONS']) @controller.Controller.must_authorized() def get_partner_address_by_id(self, **kw): diff --git a/indoteknik_api/controllers/api_v1/sale_order.py b/indoteknik_api/controllers/api_v1/sale_order.py index 1e5e8a66..ea2d381c 100644 --- a/indoteknik_api/controllers/api_v1/sale_order.py +++ b/indoteknik_api/controllers/api_v1/sale_order.py @@ -52,6 +52,7 @@ class SaleOrder(controller.Controller): params = self.get_request_params(kw, { 'partner_id': ['number'], 'name': [], + 'site': [], 'limit': ['default:0', 'number'], 'offset': ['default:0', 'number'], 'context': [] @@ -80,11 +81,11 @@ class SaleOrder(controller.Controller): ('partner_purchase_order_name', 'ilike', '%' + name + '%') ] - # if params['value']['site']: - # site = params['value']['site'].replace(' ', '%') - # domain += [ - # ('partner_id.site_id.name', 'ilike', '%' + site + '%') - # ] + if params['value']['site']: + site = params['value']['site'].replace(' ', '%') + domain += [ + ('partner_id.site_id.name', 'ilike', '%' + site + '%') + ] sale_orders = request.env['sale.order'].search( domain, offset=offset, limit=limit) @@ -330,6 +331,7 @@ class SaleOrder(controller.Controller): 'delivery_amount': ['number', 'default:0'], 'carrier_id': [], 'delivery_service_type': [], + 'flash_sale': ['boolean'], 'voucher': [], 'source': [], 'estimated_arrival_days': ['number', 'default:0'] @@ -363,6 +365,7 @@ class SaleOrder(controller.Controller): 'shipping_paid_by': 'customer', 'carrier_id': params['value']['carrier_id'], 'delivery_service_type': params['value']['delivery_service_type'], + 'flash_sale': params['value']['flash_sale'], 'customer_type': 'nonpkp', 'npwp': '0', 'user_id': 1180 # User ID: Ima Nurhikmah diff --git a/indoteknik_api/controllers/controller.py b/indoteknik_api/controllers/controller.py index 017e5c12..a34a2688 100644 --- a/indoteknik_api/controllers/controller.py +++ b/indoteknik_api/controllers/controller.py @@ -80,9 +80,10 @@ class Controller(http.Controller): 'value': {}, 'query': {} } - + for key, rules in queries.items(): is_number = 'number' in rules + is_boolean = 'boolean' in rules is_exclude_if_null = 'exclude_if_null' in rules alias = next((r.replace('alias:', '') for r in rules if r.startswith('alias:')), key) default = next((r.replace('default:', '') for r in rules if r.startswith('default:')), None) @@ -92,8 +93,10 @@ class Controller(http.Controller): value = '' if 'required' in rules and not value: result['reason'].append(f"{key} is required") - if 'number' in rules and value and not value.isdigit(): + if is_number and value and not value.isdigit(): result['reason'].append(f"{key} must be a number") + if is_boolean and value and value.lower() not in ['true', 'false', '1', '0']: + result['reason'].append(f"{key} must be a boolean") result['query'][key] = value @@ -101,6 +104,8 @@ class Controller(http.Controller): value = default if is_number and value.isdigit(): value = int(value) + if is_boolean: + value = value.lower() in ['true', '1'] if not value and is_exclude_if_null: continue @@ -108,7 +113,7 @@ class Controller(http.Controller): result['value'][alias] = value result['valid'] = not result['reason'] - + return result def time_to_str(self, object, format): diff --git a/indoteknik_api/models/res_users.py b/indoteknik_api/models/res_users.py index 2124cd2e..d5dff876 100644 --- a/indoteknik_api/models/res_users.py +++ b/indoteknik_api/models/res_users.py @@ -19,6 +19,7 @@ class ResUsers(models.Model): 'id': res_user.id, 'parent_id': res_user.parent_id.id or None, 'parent_name': res_user.parent_id.name or None, + 'site': partner.site_id.name or None, 'partner_id': partner.id, 'name': res_user.name, 'email': res_user.login, diff --git a/indoteknik_api/models/sale_order.py b/indoteknik_api/models/sale_order.py index c98834bf..88dc331f 100644 --- a/indoteknik_api/models/sale_order.py +++ b/indoteknik_api/models/sale_order.py @@ -15,8 +15,9 @@ class SaleOrder(models.Model): 'token': self.env['rest.api'].md5_salt(sale_order.id, 'sale.order'), 'id': sale_order.id, 'name': sale_order.name, + 'site_partner': sale_order.partner_id.site_id.name, 'sales': sale_order.user_id.name, - 'amount_untaxed': sale_order.amount_untaxed, + 'amount_untaxed': sale_order.amount_untaxed, 'amount_tax': sale_order.amount_tax, 'amount_total': sale_order.grand_total, 'purchase_order_name': sale_order.partner_purchase_order_name or sale_order.client_order_ref, @@ -66,6 +67,7 @@ class SaleOrder(models.Model): 'products': [], 'delivery_amount': sale_order.delivery_amt or 0, 'address': { + 'site_partner': sale_order.partner_id.site_id.name, 'customer': res_users.api_address_response(sale_order.partner_id), 'invoice': res_users.api_address_response(sale_order.partner_invoice_id), 'shipping': res_users.api_address_response(sale_order.partner_shipping_id) diff --git a/indoteknik_custom/__manifest__.py b/indoteknik_custom/__manifest__.py index 6b5bc8bb..67f16800 100755 --- a/indoteknik_custom/__manifest__.py +++ b/indoteknik_custom/__manifest__.py @@ -91,6 +91,7 @@ 'views/airway_bill.xml', 'views/product_attribute_value.xml', 'views/mail_template_po.xml', + 'views/mail_template_efaktur.xml', 'views/price_group.xml', 'views/mrp_production.xml', 'views/apache_solr.xml', @@ -131,6 +132,9 @@ 'views/def_cargo_district.xml', 'views/purchase_order_multi_uangmuka.xml', 'views/purchase_order_multi_uangmuka2.xml', + 'views/logbook_bill.xml', + 'views/report_logbook_bill.xml', + 'views/sale_order_multi_uangmuka_penjualan.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 e6fefe2a..ffd1b645 100755 --- a/indoteknik_custom/models/__init__.py +++ b/indoteknik_custom/models/__init__.py @@ -117,3 +117,6 @@ from . import ged from . import account_move_multi_update_bills from . import def_cargo from . import purchase_order_multi_uangmuka2 +from . import logbook_bill +from . import report_logbook_bill +from . import sale_order_multi_uangmuka_penjualan diff --git a/indoteknik_custom/models/account_move.py b/indoteknik_custom/models/account_move.py index 0ba25ad8..fbadd2aa 100644 --- a/indoteknik_custom/models/account_move.py +++ b/indoteknik_custom/models/account_move.py @@ -64,6 +64,34 @@ class AccountMove(models.Model): nomor_kwitansi = fields.Char(string="Nomor Kwitansi") @api.model + def generate_attachment(self, record): + # Fetch the binary field + file_content = record.efaktur_document + file_name = "efaktur_document_{}.pdf".format(record.id) # Adjust the file extension if necessary + + attachment = self.env['ir.attachment'].create({ + 'name': file_name, + 'type': 'binary', + 'datas': file_content, + 'res_model': record._name, + 'res_id': record.id, + }) + return attachment + + # @api.constrains('efaktur_document') + def send_scheduled_email(self): + # Get the records for which emails need to be sent + records = self.search([('id', 'in', self.ids)]) + template = self.env.ref('indoteknik_custom.mail_template_efaktur_document') + + for record in records: + attachment = self.generate_attachment(record) + email_values = { + 'attachment_ids': [(4, attachment.id)] + } + template.send_mail(record.id, email_values=email_values, force_send=True) + + @api.model def create(self, vals): vals['nomor_kwitansi'] = self.env['ir.sequence'].next_by_code('nomor.kwitansi') or '0' result = super(AccountMove, self).create(vals) diff --git a/indoteknik_custom/models/account_move_due_extension.py b/indoteknik_custom/models/account_move_due_extension.py index cac73d07..c9af7f8d 100644 --- a/indoteknik_custom/models/account_move_due_extension.py +++ b/indoteknik_custom/models/account_move_due_extension.py @@ -14,6 +14,7 @@ class DueExtension(models.Model): number = fields.Char(string='Document No', index=True, copy=False, readonly=True, tracking=True) partner_id = fields.Many2one('res.partner', string="Customer", readonly=True) order_id = fields.Many2one('sale.order', string="SO", readonly=True) + invoice_id = fields.Many2one('account.move', related='due_line.invoice_id', string='Invoice', readonly=False) due_line = fields.One2many('due.extension.line', 'due_id', string='Due Extension Lines', auto_join=True) old_due = fields.Date(string="Old Due") description = fields.Text(string="Description") diff --git a/indoteknik_custom/models/automatic_purchase.py b/indoteknik_custom/models/automatic_purchase.py index 2c83c0ea..73416c48 100644 --- a/indoteknik_custom/models/automatic_purchase.py +++ b/indoteknik_custom/models/automatic_purchase.py @@ -506,13 +506,15 @@ class AutomaticPurchase(models.Model): taxes = '' human_last_update = purchase_price.human_last_update or datetime.min system_last_update = purchase_price.system_last_update or datetime.min - - price = purchase_price.product_price - taxes = purchase_price.taxes_product_id.id + + if purchase_price.taxes_product_id.type_tax_use == 'purchase': + price = purchase_price.product_price + taxes = purchase_price.taxes_product_id.id if system_last_update > human_last_update: - price = purchase_price.system_price - taxes = purchase_price.taxes_system_id.id + if purchase_price.taxes_system_id.type_tax_use == 'purchase': + price = purchase_price.system_price + taxes = purchase_price.taxes_system_id.id return price, taxes diff --git a/indoteknik_custom/models/delivery_carrier.py b/indoteknik_custom/models/delivery_carrier.py index b3ae44e9..0bf1f08d 100644 --- a/indoteknik_custom/models/delivery_carrier.py +++ b/indoteknik_custom/models/delivery_carrier.py @@ -6,3 +6,4 @@ class DeliveryCarrier(models.Model): pic_name = fields.Char(string='PIC Name') pic_phone = fields.Char(string='PIC Phone') + address = fields.Char(string='Address') diff --git a/indoteknik_custom/models/logbook_bill.py b/indoteknik_custom/models/logbook_bill.py new file mode 100644 index 00000000..578ad59b --- /dev/null +++ b/indoteknik_custom/models/logbook_bill.py @@ -0,0 +1,103 @@ +from odoo import models, fields, api, _ +from odoo.exceptions import UserError +from pytz import timezone +from datetime import datetime + +class LogbookBill(models.TransientModel): + _name = 'logbook.bill' + + name = fields.Char(string='Name', default='Logbook Bill') + logbook_bill_line = fields.One2many( + comodel_name='logbook.bill.line', + inverse_name='logbook_bill_id', + string='Logbook Bill Line' + ) + + + def grand_total(self, picking): + total = 0 + for line in picking.move_ids_without_package: + po = self.env['purchase.order.line'].search([ + ('order_id', '=', picking.purchase_id.id), + ('product_id', '=', line.product_id.id), + ], order='id desc', limit=1) + total += line.quantity_done * po.price_unit + return total + + def create_logbook_bill(self): + logbook_line = self.logbook_bill_line + + current_time = datetime.utcnow() + report_logbook_ids = [] + parameters_header = { + 'date': current_time, + 'created_by': self.env.user.id, + } + + report_logbook = self.env['report.logbook.bill'].create([parameters_header]) + for line in logbook_line: + picking = self.env['stock.picking'].search([('name', '=', line.name)], limit=1) + stock = picking + parent_id = stock.partner_id.parent_id.id + parent_id = parent_id if parent_id else stock.partner_id.id + + data = { + 'purchase_id': stock.purchase_id.id, + 'name': stock.name, + 'grand_total': self.grand_total(picking), + 'partner_id': parent_id, + 'invoice': line.invoice, + 'surat_jalan': line.surat_jalan, + 'proforma_invoice': line.proforma_invoice, + 'faktur_pajak': line.faktur_pajak, + 'date_approve': stock.date_done, + 'report_logbook_bill_id': report_logbook.id, + 'note': line.note, + 'note_finance': line.note_finance + } + self.env['report.logbook.bill.line'].create([data]) + + report_logbook_ids.append(report_logbook.id) + line.unlink() + + self.unlink() + return { + 'name': _('Report Logbook Bill'), + 'view_mode': 'tree,form', + 'res_model': 'report.logbook.bill', + 'target': 'current', + 'type': 'ir.actions.act_window', + 'domain': [('id', 'in', report_logbook_ids)], + } + +class LogbookBillLine(models.TransientModel): + _name = 'logbook.bill.line' + + name = fields.Char(string='Name') + logbook_bill_id = fields.Many2one('logbook.bill', string='Logbook Bill') + partner_id = fields.Many2one('res.partner', string='Customer') + purchase_id = fields.Many2one('purchase.order', string='Purchase Order') + invoice = fields.Boolean(string='Invoice') + faktur_pajak = fields.Boolean(string='Faktur Pajak') + surat_jalan = fields.Boolean(string='Surat Jalan') + proforma_invoice = fields.Boolean(string='Proforma Invoice') + date_approve = fields.Datetime(string='Date Approve', tracking=3) + note = fields.Char(string='Note Logistik') + note_finance = fields.Char(string='Note Finance') + + @api.onchange('name') + def onchange_name(self): + current_time = datetime.now(timezone('Asia/Jakarta')).strftime('%Y-%m-%d %H:%M:%S') + + if self.name: + if len(self.name) == 13: + self.name = self.name[:-1] + picking = self.env['stock.picking'].search([('name', '=', self.name)], limit=1) + if picking: + self.partner_id = picking.partner_id + self.purchase_id = picking.purchase_id.id + + self.date_approve = picking.date_done + + else: + raise UserError('Nomor DO tidak ditemukan') diff --git a/indoteknik_custom/models/manufacturing.py b/indoteknik_custom/models/manufacturing.py index 2455a117..37c4e909 100644 --- a/indoteknik_custom/models/manufacturing.py +++ b/indoteknik_custom/models/manufacturing.py @@ -23,7 +23,9 @@ class Manufacturing(models.Model): def button_mark_done(self): if self._name != 'mrp.production': return super(Manufacturing, self).button_mark_done() - + # Check product category + if self.product_id.categ_id.name != 'Finish Good': + raise UserError('Tidak bisa di complete karna product category bukan Unit / Finish Good') for line in self.move_raw_ids: # if line.quantity_done > 0 and line.quantity_done != self.product_uom_qty: # raise UserError('Qty Consume per Line tidak sama dengan Qty to Produce') diff --git a/indoteknik_custom/models/purchase_order.py b/indoteknik_custom/models/purchase_order.py index 7b0fa20c..4a029441 100755 --- a/indoteknik_custom/models/purchase_order.py +++ b/indoteknik_custom/models/purchase_order.py @@ -60,6 +60,60 @@ class PurchaseOrder(models.Model): matches_so = fields.Many2many('sale.order', string='Matches SO', compute='_compute_matches_so') is_create_uangmuka = fields.Boolean(string='Uang Muka?') move_id = fields.Many2one('account.move', string='Account Move') + logbook_bill_id = fields.Many2one('report.logbook.bill', string='Logbook Bill') + status_printed = fields.Selection([ + ('not_printed', 'Belum Print'), + ('printed', 'Printed') + ], string='Printed?', copy=False, tracking=True) + + def _prepare_invoice(self): + """Prepare the dict of values to create the new invoice for a purchase order. + """ + self.ensure_one() + move_type = self._context.get('default_move_type', 'in_invoice') + journal = self.env['account.move'].with_context(default_move_type=move_type)._get_default_journal() + if not journal: + raise UserError(_('Please define an accounting purchase journal for the company %s (%s).') % (self.company_id.name, self.company_id.id)) + + stock_picking = self.env['stock.picking'].search([ + ('purchase_id', '=', self.id), + ('state', '=', 'done') + ], order='date_done desc', limit=1) + + date_done = stock_picking.date_done + + day_extension = int(self.payment_term_id.line_ids.days) + payment_schedule = date_done + timedelta(days=day_extension) + + if payment_schedule.weekday() == 0: + payment_schedule -= timedelta(days=4) + elif payment_schedule.weekday() == 2: + payment_schedule -= timedelta(days=1) + elif payment_schedule.weekday() == 4: + payment_schedule -= timedelta(days=1) + elif payment_schedule.weekday() == 5: + payment_schedule -= timedelta(days=2) + elif payment_schedule.weekday() == 6: + payment_schedule -= timedelta(days=3) + + partner_invoice_id = self.partner_id.address_get(['invoice'])['invoice'] + invoice_vals = { + 'ref': self.partner_ref or '', + 'move_type': move_type, + 'narration': self.notes, + 'currency_id': self.currency_id.id, + 'invoice_user_id': self.user_id and self.user_id.id or self.env.user.id, + 'partner_id': partner_invoice_id, + 'fiscal_position_id': (self.fiscal_position_id or self.fiscal_position_id.get_fiscal_position(partner_invoice_id)).id, + 'payment_reference': self.partner_ref or '', + 'partner_bank_id': self.partner_id.bank_ids[:1].id, + 'invoice_origin': self.name, + 'invoice_payment_term_id': self.payment_term_id.id, + 'invoice_line_ids': [], + 'company_id': self.company_id.id, + 'payment_schedule': payment_schedule + } + return invoice_vals def _compute_matches_so(self): for po in self: @@ -389,6 +443,12 @@ class PurchaseOrder(models.Model): for line in self.order_line: if not line.product_id.purchase_ok: raise UserError("Terdapat barang yang tidak bisa diproses") + # Validasi pajak + if not line.taxes_id: + raise UserError("Masukkan Tax untuk produk") + for tax in line.taxes_id: + if tax.type_tax_use != 'purchase': + raise UserError("Pastikan Tax Category nya adalah Purchase pada produk %s" % line.product_id.name) if line.price_unit != line.price_vendor and line.price_vendor != 0: self._send_po_not_sync() send_email = True @@ -589,63 +649,6 @@ class PurchaseOrder(models.Model): self.total_so_margin = 0 self.total_so_percent_margin = 0 - # def compute_total_margin_from_apo(self): - # purchase_price_dict = {} - - - # for line in self.order_sales_match_line: - # for lines in self.order_line: - # product_id = lines.product_id.id - - # if product_id not in purchase_price_dict: - # purchase_price_dict[product_id] = lines.price_subtotal - - # sum_so_margin = sum_sales_price = sum_margin = 0 - # sale_order_line = line.sale_line_id - - # if not sale_order_line: - # sale_order_line = self.env['sale.order.line'].search([ - # ('product_id', '=', line.product_id.id), - # ('order_id', '=', line.sale_id.id) - # ], limit=1, order='price_reduce_taxexcl') - - # sum_so_margin += sale_order_line.item_margin - - # # sales_price = sale_order_line.price_reduce_taxexcl * line.qty_so - # sales_price = sale_order_line.price_reduce_taxexcl * lines.product_qty - - # if sale_order_line.order_id.shipping_cost_covered == 'indoteknik': - # sales_price -= sale_order_line.delivery_amt_line - - # if sale_order_line.order_id.fee_third_party > 0: - # sales_price -= sale_order_line.fee_third_party_line - - # sum_sales_price += sales_price - - # product_id = sale_order_line.product_id.id - - # purchase_price = purchase_price_dict.get(product_id, 0) - # # purchase_price = lines.price_subtotal - # if lines.order_id.delivery_amount > 0: - # purchase_price += lines.delivery_amt_line - - # if line.purchase_order_id.delivery_amount > 0: - # purchase_price += line.delivery_amt_line - - # real_item_margin = sales_price - purchase_price - # sum_margin += real_item_margin - - # if sum_so_margin != 0 and sum_sales_price != 0 and sum_margin != 0: - # self.total_so_margin = sum_so_margin - # self.total_so_percent_margin = round((sum_so_margin / sum_sales_price), 2) * 100 - # self.total_margin = sum_margin - # self.total_percent_margin = round((sum_margin / sum_sales_price), 2) * 100 - # else: - # self.total_margin = 0 - # self.total_percent_margin = 0 - # self.total_so_margin = 0 - # self.total_so_percent_margin = 0 - def compute_amt_total_without_service(self): for order in self: sum_price_total = 0 diff --git a/indoteknik_custom/models/purchasing_job.py b/indoteknik_custom/models/purchasing_job.py index 373e469a..40061d22 100644 --- a/indoteknik_custom/models/purchasing_job.py +++ b/indoteknik_custom/models/purchasing_job.py @@ -41,14 +41,13 @@ class PurchasingJob(models.Model): } def init(self): - tools.drop_view_if_exists(self.env.cr, self._table) - self.env.cr.execute(""" + query = """ CREATE OR REPLACE VIEW %s AS ( WITH latest_purchase_orders AS ( SELECT pol.product_id, po.user_id, - ROW_NUMBER() OVER (PARTITION BY po.partner_id ORDER BY po.create_date DESC) AS order_rank + ROW_NUMBER() OVER (PARTITION BY pol.product_id ORDER BY po.create_date DESC) AS order_rank FROM purchase_order po RIGHT JOIN purchase_order_line pol ON pol.order_id = po.id LEFT JOIN res_partner rp ON rp.id = po.partner_id @@ -70,11 +69,26 @@ class PurchasingJob(models.Model): LEFT JOIN sale_order_line sol ON sol.id = vso.sale_line_id ) AS sub WHERE sub.vendor_id IS NOT NULL + ), + unique_sub AS ( + SELECT DISTINCT + vso.product_id, + sol.vendor_id + FROM v_sales_outstanding vso + LEFT JOIN sale_order_line sol ON sol.id = vso.sale_line_id + WHERE sol.vendor_id IS NOT NULL + ), + latest_po_filtered AS ( + SELECT + product_id, + user_id + FROM latest_purchase_orders + WHERE order_rank = 1 ) SELECT pmp.product_id AS id, pmp.product_id, - sub.vendor_id, + MAX(sub.vendor_id) AS vendor_id, pmp.brand, pmp.item_code, pmp.product, @@ -84,30 +98,23 @@ class PurchasingJob(models.Model): pmp.action, MAX(pjs.status_apo) AS status_apo, MAX(pjs.note) AS note, - ru.user_id AS purchase_representative_id + MAX(ru.user_id) AS purchase_representative_id FROM v_procurement_monitoring_by_product pmp LEFT JOIN purchasing_job_state pjs ON pjs.purchasing_job_id = pmp.product_id - LEFT JOIN ( - SELECT - vso.product_id, - sol.vendor_id - FROM v_sales_outstanding vso - LEFT JOIN sale_order_line sol ON sol.id = vso.sale_line_id - ) AS sub ON sub.product_id = pmp.product_id - LEFT JOIN latest_purchase_orders po ON po.product_id = pmp.product_id + LEFT JOIN unique_sub sub ON sub.product_id = pmp.product_id + LEFT JOIN latest_po_filtered po ON po.product_id = pmp.product_id LEFT JOIN random_user_ids ru ON ru.vendor_id = sub.vendor_id OR (ru.vendor_id IS NULL AND sub.vendor_id != 9688) WHERE pmp.action = 'kurang' - AND sub.vendor_id IS NOT NULL + AND sub.vendor_id IS NOT NULL GROUP BY pmp.product_id, pmp.brand, pmp.item_code, pmp.product, - pmp.action, - sub.vendor_id, - ru.user_id - ) - """ % self._table) + pmp.action + )""" % self._table + + self.env.cr.execute(query) def open_form_multi_generate_request_po(self): diff --git a/indoteknik_custom/models/purchasing_job_multi_update.py b/indoteknik_custom/models/purchasing_job_multi_update.py index deba960a..80a43e45 100644 --- a/indoteknik_custom/models/purchasing_job_multi_update.py +++ b/indoteknik_custom/models/purchasing_job_multi_update.py @@ -18,7 +18,7 @@ class PurchasingJobMultiUpdate(models.TransientModel): ('purchasing_job_id', '=', product.id) ]) - purchasing_job_state.unlink() + # purchasing_job_state.unlink() purchasing_job_state.create({ 'purchasing_job_id': product.id, diff --git a/indoteknik_custom/models/report_logbook_bill.py b/indoteknik_custom/models/report_logbook_bill.py new file mode 100644 index 00000000..9a7c1535 --- /dev/null +++ b/indoteknik_custom/models/report_logbook_bill.py @@ -0,0 +1,98 @@ +from odoo import models, fields, api +from odoo.exceptions import UserError +from pytz import timezone +from datetime import datetime + +class ReportLogbookBill(models.Model): + _name = 'report.logbook.bill' + _description = "Logbook Bill" + _inherit = ['mail.thread'] + _rec_name = 'name' + + name = fields.Char(string='Name', default='Logbook Bill') + date = fields.Datetime(string='Date Created') + date_approve = fields.Datetime(string='Date Approve', tracking=3) + date_pengajuan = fields.Datetime(string='Date Pengajuan', tracking=3) + approve_by_finance = fields.Boolean(string='Approve By Finance', tracking=3) + pengajuan_by = fields.Many2one(comodel_name='res.users', string='Pengajuan By', tracking=3) + approve_by = fields.Many2one(comodel_name='res.users', string='Approve By', tracking=3) + created_by = fields.Many2one(comodel_name='res.users', string='Created By', tracking=3) + report_logbook_bill_line = fields.One2many( + comodel_name='report.logbook.bill.line', + inverse_name='report_logbook_bill_id', + string='Logbook Bill Line' + ) + state = fields.Selection( + [('belum_terima', 'Belum Terima'), + ('terima_sebagian', 'Terima Sebagian'), + ('terima_semua', 'Sudah di terima semua'), + ], + default='terima_semua', + string='Status', + tracking=True, + ) + + state_pengajuan = fields.Selection( + [('pengajuan', 'Pengajuan'), + ('diajukan', 'Sudah Diajukan'), + ], + default='pengajuan', + string='Status Pengajuan', + tracking=True, + ) + + count_line = fields.Char(string='Count Line', compute='_compute_count_line') + + @api.depends('report_logbook_bill_line') + def _compute_count_line(self): + for rec in self: + rec.count_line = len(rec.report_logbook_bill_line) + + @api.model + def create(self, vals): + vals['name'] = self.env['ir.sequence'].next_by_code('report.logbook.bill') or '0' + result = super(ReportLogbookBill, self).create(vals) + return result + + def approve(self): + current_time = datetime.utcnow() + if self.env.user.is_accounting: + self.approve_by_finance = True + self.date_approve = current_time + self.approve_by = self.env.user.id + if any(line.not_exist for line in self.report_logbook_bill_line): + if all(line.not_exist for line in self.report_logbook_bill_line): + self.state = 'belum_terima' + else: + self.state = 'terima_sebagian' + else: + self.state = 'terima_semua' + 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: + line.purchase_id.logbook_bill_id = self.id + +class ReportLogbookBillLine(models.Model): + _name = 'report.logbook.bill.line' + + name = fields.Char(string='Name') + logbook_bill_id = fields.Many2one('report.logbook.bill', string='Logbook Bill') + purchase_id = fields.Many2one('purchase.order', string='Purchase Order') + invoice = fields.Boolean(string='Invoice') + faktur_pajak = fields.Boolean(string='FP') + surat_jalan = fields.Boolean(string='SJ') + purchase_id = fields.Many2one('purchase.order', string='Purchase Order') + partner_id = fields.Many2one('res.partner', string='Customer') + proforma_invoice = fields.Boolean(string='Proforma Inv') + report_logbook_bill_id = fields.Many2one('report.logbook.bill', string='Logbook Bill') + not_exist = fields.Boolean(string='Not Exist') + date_approve = fields.Datetime(string='Date Approve', tracking=3) + grand_total = fields.Float(string='Grand Total') + note = fields.Char(string='Note Logistik') + note_finance = fields.Char(string='Note Finance') diff --git a/indoteknik_custom/models/report_stock_forecasted.py b/indoteknik_custom/models/report_stock_forecasted.py index 92da13d5..d5e48fdc 100644 --- a/indoteknik_custom/models/report_stock_forecasted.py +++ b/indoteknik_custom/models/report_stock_forecasted.py @@ -10,28 +10,29 @@ class ReplenishmentReport(models.AbstractModel): for line in lines: document_out = line.get('document_out') - order_id = document_out.id if document_out else None - product_id = line.get('product', {}).get('id') - query = [('product_id', '=', product_id)] - if order_id: - result = self._calculate_result(line) - quantity = line.get('quantity', 0) - result_dict.setdefault(order_id, []).append((result, quantity)) + if document_out and "SO/" in document_out.name: + order_id = document_out.id + product_id = line.get('product', {}).get('id') + query = [('product_id', '=', product_id)] - for order_id, results in result_dict.items(): - sales_order = self.env['sale.order'].browse(order_id) + if order_id: + result = self._calculate_result(line) + quantity = line.get('quantity', 0) + result_dict.setdefault(order_id, []).append((result, quantity)) - for result, quantity in results: - self.env['sales.order.fullfillment'].create({ - 'sales_order_id': sales_order.id, - 'product_id': product_id, - 'reserved_from': result, - 'qty_fullfillment': quantity, - }) + for order_id, results in result_dict.items(): + sales_order = self.env['sale.order'].browse(order_id) + for result, quantity in results: + self.env['sales.order.fullfillment'].create({ + 'sales_order_id': sales_order.id, + 'product_id': product_id, + 'reserved_from': result, + 'qty_fullfillment': quantity, + }) - return lines + return lines def _calculate_result(self, line): if line['document_in']: diff --git a/indoteknik_custom/models/sale_order.py b/indoteknik_custom/models/sale_order.py index 91792b59..ac81737d 100755 --- a/indoteknik_custom/models/sale_order.py +++ b/indoteknik_custom/models/sale_order.py @@ -2,6 +2,7 @@ from odoo import fields, models, api, _ from odoo.exceptions import UserError, ValidationError from datetime import datetime, timedelta import logging, random, string, requests, math, json, re +from collections import defaultdict _logger = logging.getLogger(__name__) @@ -9,7 +10,7 @@ _logger = logging.getLogger(__name__) class SaleOrder(models.Model): _inherit = "sale.order" - # fullfillment_line = fields.One2many('sales.order.fullfillment', 'sales_order_id', string='Fullfillment') + fullfillment_line = fields.One2many('sales.order.fullfillment', 'sales_order_id', string='Fullfillment') order_sales_match_line = fields.One2many('sales.order.purchase.match', 'sales_order_id', string='Purchase Match Lines', states={'cancel': [('readonly', True)], 'done': [('readonly', True)]}, copy=True) total_margin = fields.Float('Total Margin', compute='_compute_total_margin', help="Total Margin in Sales Order Header") total_percent_margin = fields.Float('Total Percent Margin', compute='_compute_total_percent_margin', help="Total % Margin in Sales Order Header") @@ -90,22 +91,31 @@ class SaleOrder(models.Model): picking_iu_id = fields.Many2one('stock.picking', 'Picking IU') helper_by_id = fields.Many2one('res.users', 'Helper By') eta_date = fields.Datetime(string='ETA Date', copy=False, compute='_compute_eta_date') + flash_sale = fields.Boolean(string='Flash Sale', help='Data dari web') web_approval = fields.Selection([ ('company', 'Company'), ('cust_manager', 'Customer Manager'), ('cust_director', 'Customer Director'), ('cust_procurement', 'Customer Procurement') ], string='Web Approval', copy=False) - # compute_fullfillment = fields.Boolean(string='Compute Fullfillment', compute="_compute_fullfillment") + compute_fullfillment = fields.Boolean(string='Compute Fullfillment', compute="_compute_fullfillment") + note_ekspedisi = fields.Char(string="Note Ekspedisi") + + def open_form_multi_create_uang_muka(self): + action = self.env['ir.actions.act_window']._for_xml_id('indoteknik_custom.action_sale_order_multi_uangmuka') + action['context'] = { + 'so_ids': [x.id for x in self] + } + return action - # def _compute_fullfillment(self): - # for rec in self: - # rec.fullfillment_line.unlink() + def _compute_fullfillment(self): + for rec in self: + rec.fullfillment_line.unlink() - # for line in rec.order_line: - # line._compute_reserved_from() + for line in rec.order_line: + line._compute_reserved_from() - # rec.compute_fullfillment = True + rec.compute_fullfillment = True def _compute_eta_date(self): max_leadtime = 0 @@ -453,6 +463,8 @@ 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 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") if order.validate_partner_invoice_due(): return self._create_notification_action('Notification', 'Terdapat invoice yang telah melewati batas waktu, mohon perbarui pada dokumen Due Extension') @@ -466,11 +478,75 @@ class SaleOrder(models.Model): raise UserError("Bisa langsung Confirm") - def send_notif_to_salesperson(self): - for rec in self: - if not rec.partner_id.main_parent_id.use_so_approval: continue - template = self.env.ref('indoteknik_custom.mail_template_sale_order_notification_to_salesperson') - template.send_mail(rec.id, force_send=True) + def send_notif_to_salesperson(self, cancel=False): + + if not cancel: + grouping_so = self.search([ + ('partner_id.parent_id.id', '=', self.partner_id.parent_id.id), + ('partner_id.site_id.id', '=', self.partner_id.site_id.id), + ]) + else: + grouping_so = self.search([ + ('partner_id.parent_id.id', '=', self.partner_id.parent_id.id), + ('partner_id.site_id.id', '=', self.partner_id.site_id.id), + ('id', '!=', self.id), + ]) + # Kelompokkan data berdasarkan salesperson + salesperson_data = {} + for rec in grouping_so: + if rec.user_id.id not in salesperson_data: + salesperson_data[rec.user_id.id] = {'name': rec.user_id.name, 'orders': [], 'total_amount': 0, 'sum_total_amount': 0, 'business_partner': '', 'site': ''} # Menetapkan nilai awal untuk 'site' + if rec.picking_ids: + if not any(picking.state in ['assigned', 'confirmed', 'waiting'] for picking in rec.picking_ids): + continue + if all(picking.state == 'done' for picking in rec.picking_ids): + continue + if all(picking.state == 'cancel' for picking in rec.picking_ids): + continue + if not rec.partner_id.main_parent_id.use_so_approval: + continue + order_total_amount = rec.amount_total # Mengakses langsung rec.amount_total + salesperson_data[rec.user_id.id]['orders'].append({ + 'order_name': rec.name, + 'parent_name': rec.partner_id.name, + 'site_name': rec.partner_id.site_id.name, + 'total_amount': rec.amount_total, + }) + salesperson_data[rec.user_id.id]['sum_total_amount'] += order_total_amount + salesperson_data[rec.user_id.id]['business_partner'] = grouping_so[0].partner_id.main_parent_id.name + salesperson_data[rec.user_id.id]['site'] = grouping_so[0].partner_id.site_id.name # Menambahkan nilai hanya jika ada + + # Kirim email untuk setiap salesperson + for salesperson_id, data in salesperson_data.items(): + if data['orders']: + # Buat isi tabel untuk email + table_content = '' + for order_data in data['orders']: + table_content += f""" + <tr> + <td>{order_data['order_name']}</td> + <td>{order_data['parent_name']}</td> + <td>{order_data['site_name']}</td> + <td>{order_data['total_amount']}</td> + </tr> + """ + + # Dapatkan email salesperson + salesperson_email = self.env['res.users'].browse(salesperson_id).partner_id.email + + # Kirim email hanya jika ada data yang dikumpulkan + template = self.env.ref('indoteknik_custom.mail_template_sale_order_notification_to_salesperson') + email_body = template.body_html.replace('${table_content}', table_content) + email_body = email_body.replace('${salesperson_name}', data['name']) + email_body = email_body.replace('${sum_total_amount}', str(data['sum_total_amount'])) + email_body = email_body.replace('${site}', str(data['site'])) + email_body = email_body.replace('${business_partner}', str(data['business_partner'])) + # Kirim email + self.env['mail.mail'].create({ + 'subject': 'Notification: Sale Orders', + 'body_html': email_body, + 'email_to': salesperson_email, + }).send() def action_confirm(self): for order in self: @@ -483,6 +559,9 @@ class SaleOrder(models.Model): if FROM_WEBSITE and main_parent.use_so_approval and order.web_approval not in ['cust_procurement', 'cust_director']: raise UserError("This order not yet approved by customer procurement or director") + + 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") if order.validate_partner_invoice_due(): return self._create_notification_action('Notification', 'Terdapat invoice yang telah melewati batas waktu, mohon perbarui pada dokumen Due Extension') @@ -505,6 +584,7 @@ class SaleOrder(models.Model): def action_cancel(self): # TODO stephan prevent cancel if have invoice, do, and po + main_parent = self.partner_id.get_main_parent() if self._name != 'sale.order': return super(SaleOrder, self).action_cancel() @@ -520,6 +600,8 @@ class SaleOrder(models.Model): self.approval_status = False self.due_id = False + if main_parent.use_so_approval: + self.send_notif_to_salesperson(cancel=True) return super(SaleOrder, self).action_cancel() def validate_partner_invoice_due(self): diff --git a/indoteknik_custom/models/sale_order_line.py b/indoteknik_custom/models/sale_order_line.py index 509e3d1c..d362d573 100644 --- a/indoteknik_custom/models/sale_order_line.py +++ b/indoteknik_custom/models/sale_order_line.py @@ -110,9 +110,13 @@ class SaleOrderLine(models.Model): 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') + self.purchase_price = self._get_valid_purchase_price(purchase_price) else: - # purchase_price = self.env['purchase.pricelist'].search( - # [('vendor_id', '=', self.vendor_id.id), ('product_id', '=', self.product_id.id)], limit=1) 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') @@ -136,11 +140,15 @@ class SaleOrderLine(models.Model): 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( - [('product_id', '=', self.product_id.id)], limit=1, order='count_trx_po desc, count_trx_po_vendor desc') + query, limit=1, order='count_trx_po desc, count_trx_po_vendor desc') line.vendor_id = purchase_price.vendor_id line.tax_id = line.order_id.sales_tax_id - line.purchase_price = self._get_valid_purchase_price(purchase_price) + line.purchase_price = line._get_valid_purchase_price(purchase_price) line_name = ('[' + line.product_id.default_code + ']' if line.product_id.default_code else '') + ' ' + (line.product_id.name if line.product_id.name else '') + ' ' + \ ('(' + line.product_id.product_template_attribute_value_ids.name + ')' if line.product_id.product_template_attribute_value_ids.name else '') + ' ' + \ diff --git a/indoteknik_custom/models/sale_order_multi_uangmuka_penjualan.py b/indoteknik_custom/models/sale_order_multi_uangmuka_penjualan.py new file mode 100644 index 00000000..f9120290 --- /dev/null +++ b/indoteknik_custom/models/sale_order_multi_uangmuka_penjualan.py @@ -0,0 +1,136 @@ +from odoo import fields, models, _, api +from odoo.exceptions import UserError +from datetime import datetime +from odoo.http import request + +import logging, math + +_logger = logging.getLogger(__name__) + + +class PurchaseOrderMultiUangmukaPenjualan(models.TransientModel): + _name = 'sale.order.multi_uangmuka_penjualan' + _description = 'digunakan untuk membuat Uang Muka Penjualan' + + pay_amt = fields.Float(string='Uang Muka', help='berapa nilai yang terbentuk untuk COA Uang Muka Pembelian') + account_id = fields.Many2one('account.account', string='Bank Intransit', default=389, help='pilih COA intransit bank') + ongkir_amt = fields.Float(string='Ongkir', help='masukan nilai yang akan menjadi Pendapatan Ongkos Kirim') + selisih_amt = fields.Float(string='Selisih', help='masukan nilai yang akan menjadi Selisih Pembayaran') + total_amt = fields.Float(string='Total', help='Total yang akan masuk di journal entries') + + @api.onchange('pay_amt', 'ongkir_amt', 'selisih_amt') + def _compute_total_amt(self): + for o in self: + o.total_amt = o.pay_amt + o.ongkir_amt + o.selisih_amt + + def create_uangmukapenjualanselected(self): + so_ids = self._context['so_ids'] + orders = self.env['sale.order'].browse(so_ids) + po_is_uangmuka = self.env['sale.order'].search([ + ('id', 'in', [x.id for x in orders]) + ]) + + if not self.account_id: + raise UserError('Bank Intransit harus diisi') + if not self.env.user.has_group('account.group_account_manager'): + raise UserError('Hanya Finance yang dapat membuat Uang Muka penjualan') + + current_time = datetime.now() + + is_have_ongkir = is_have_selisih = False + if self.ongkir_amt > 0: + is_have_ongkir = True + if not math.isclose(self.selisih_amt, 0): + is_have_selisih = True + + partner_name = orders[0].partner_id.name + if orders[0].partner_id.parent_id: + partner_name = orders[0].partner_id.parent_id.name + + order_names = ', '.join([data.name for data in orders]) # Menggabungkan nama order menjadi satu string + ref_label = f'UANG MUKA PENJUALAN {order_names} {partner_name}' + param_header = { + 'ref': ref_label, + 'date': current_time, + 'journal_id': 11, + # 'sale_id': order.id, + } + + account_move = self.env['account.move'].create([param_header]) + debit_entries = [] + pay_amt = 0 + + + for order in orders: + _logger.info('Success Create Uang Muka P %s' % account_move.name) + partner_id = order.partner_id.parent_id.id if order.partner_id.parent_id else order.partner_id.id + partner = order.partner_id.parent_id.name if order.partner_id.parent_id else order.partner_id.name + + param_credit = { + 'move_id': account_move.id, + 'account_id': 449, # uang muka penjualan + 'partner_id': partner_id, + 'currency_id': 12, + 'debit': 0, + 'credit': order.amount_total, + 'name': f'UANG MUKA PENJUALAN {order.name} {partner}', + } + param_ongkir_credit = { + 'move_id': account_move.id, + 'account_id': 550, # pendapatan ongkos kirim + 'partner_id': partner_id, + 'currency_id': 12, + 'debit': 0, + 'credit': self.ongkir_amt, + 'name': f'UANG MUKA PENJUALAN {order.name} {partner}', + } + param_selisih_credit = { + 'move_id': account_move.id, + 'account_id': 561, # selisih pembayaran + 'partner_id': partner_id, + 'currency_id': 12, + 'debit': 0, + 'credit': self.selisih_amt, + 'name': f'UANG MUKA PENJUALAN {order.name} {partner}', + } + + debit_entries.append(param_credit) + pay_amt += order.amount_total + + if is_have_ongkir: + debit_entries.append(param_ongkir_credit) + pay_amt += self.ongkir_amt + + if is_have_selisih: + debit_entries.append(param_selisih_credit) + pay_amt += self.selisih_amt + + param_debit = { + 'move_id': account_move.id, + 'account_id': self.account_id.id, # intransit + 'partner_id': partner_id, + 'currency_id': 12, + 'debit': pay_amt, + 'credit': 0, + 'name': ref_label, + } + + debit_entries.append(param_debit) + + # Create all account.move.line entries at once + self.env['account.move.line'].create(debit_entries) + + return { + 'name': _('Journal Entries'), + 'view_mode': 'form', + 'res_model': 'account.move', + 'target': 'current', + 'view_id': False, + 'type': 'ir.actions.act_window', + 'res_id': account_move.id + } + + # def save_multi_create_uang_muka(self): + + # account_move = self.create_uangmukapenjualanselected(purchase, is_create_uangmuka) +
\ No newline at end of file diff --git a/indoteknik_custom/models/solr/apache_solr.py b/indoteknik_custom/models/solr/apache_solr.py index 397db53b..6560c9b5 100644 --- a/indoteknik_custom/models/solr/apache_solr.py +++ b/indoteknik_custom/models/solr/apache_solr.py @@ -294,23 +294,26 @@ class ApacheSolr(models.Model): return False def _solr_sync_recommendation(self, limit=100): - solr_model = self.env['apache.solr'] variants = self.env['product.product'].search([('solr_flag', '=', 2)], limit=limit) - # documents = [] + documents = [] + catch = {} for variant in variants: - # document = solr_model.get_doc('recommendation', variant.id) - document = {} - document.update({ - 'id': variant.id, - 'display_name_s': variant.display_name, - 'name_s': variant.name, - 'default_code_s': variant.default_code or '', - 'product_rating_f': variant.product_tmpl_id.virtual_rating, - 'template_id_i': variant.product_tmpl_id.id, - 'active_s': variant.active, - }) - # self.solr().add(docs=[document], softCommit=True) - # documents.append(document) - variant.solr_flag = 1 - _recommendation_solr.add(document) - # _recommendation_solr.add(documents) + try: + document = { + 'id': variant.id or 0, + 'display_name_s': variant.display_name or '', + 'name_s': variant.name or '', + 'default_code_s': variant.default_code or '', + 'product_rating_f': variant.product_tmpl_id.virtual_rating or 0, + 'template_id_i': variant.product_tmpl_id.id or 0, + 'active_s': str(variant.active) or 'false', + 'type_s': variant.product_tmpl_id.type or '', + } + variant.write({'solr_flag': 1}) # Ensure the flag is updated correctly + documents.append(document) + catch = document + except Exception as e: + _logger.error("Failed to add document to Solr: %s", e) + _logger.error("Document data: %s", catch) + _recommendation_solr.add(documents) + return True diff --git a/indoteknik_custom/security/ir.model.access.csv b/indoteknik_custom/security/ir.model.access.csv index ae622ba4..30bc7d06 100755 --- a/indoteknik_custom/security/ir.model.access.csv +++ b/indoteknik_custom/security/ir.model.access.csv @@ -122,3 +122,9 @@ access_def_cargo_city,access.def.cargo.city,model_def_cargo_city,,1,1,1,1 access_def_cargo_district,access.def.cargo.district,model_def_cargo_district,,1,1,1,1 access_purchase_order_multi_uangmuka,access.purchase.order.multi_uangmuka,model_purchase_order_multi_uangmuka,,1,1,1,1 access_purchase_order_multi_uangmuka2,access.purchase.order.multi_uangmuka2,model_purchase_order_multi_uangmuka2,,1,1,1,1 +access_logbook_bill,access.logbook.sj,model_logbook_bill,,1,1,1,1 +access_logbook_bill_line,access.logbook.sj.line,model_logbook_bill_line,,1,1,1,1 +access_report_logbook_bill,access.report.logbook.sj,model_report_logbook_bill,,1,1,1,1 +access_report_logbook_bill_line,access.report.logbook.sj.line,model_report_logbook_bill_line,,1,1,1,1 +access_report_logbook_bill_line,access.report.logbook.sj.line,model_report_logbook_bill_line,,1,1,1,1 +access_sale_order_multi_uangmuka_penjualan,access.sale.order.multi_uangmuka_penjualan,model_sale_order_multi_uangmuka_penjualan,,1,1,1,1 diff --git a/indoteknik_custom/views/account_move_views.xml b/indoteknik_custom/views/account_move_views.xml index fee94b42..1c70cc7b 100644 --- a/indoteknik_custom/views/account_move_views.xml +++ b/indoteknik_custom/views/account_move_views.xml @@ -33,54 +33,67 @@ </field> </record> -<record id="due_extension_form" model="ir.ui.view"> - <field name="name">due.extension.form</field> - <field name="model">due.extension</field> - <field name="arch" type="xml"> - <form create="false"> - <header> - <button name="approve_new_due" - string="Approve" - type="object" - /> - <button name="due_extension_approval" - string="Ask Approval" - type="object" - /> - <button name="due_extension_cancel" - string="Cancel" + <record id="due_extension_form" model="ir.ui.view"> + <field name="name">due.extension.form</field> + <field name="model">due.extension</field> + <field name="arch" type="xml"> + <form create="false"> + <header> + <button name="approve_new_due" + string="Approve" type="object" - /> - </header> - <sheet> - <group> + /> + <button name="due_extension_approval" + string="Ask Approval" + type="object" + /> + <button name="due_extension_cancel" + string="Cancel" + type="object" + /> + </header> + <sheet> <group> - <field name="partner_id" readonly="1"/> - <field name="day_extension" attrs="{'readonly': [('is_approve', '=', True)]}"/> + <group> + <field name="partner_id" readonly="1"/> + <field name="day_extension" attrs="{'readonly': [('is_approve', '=', True)]}"/> + </group> + <group> + <field name="is_approve" readonly="1"/> + <field name="order_id" readonly="1"/> + <field name="counter" readonly="1"/> + <field name="approval_status" readonly="1"/> + </group> </group> <group> - <field name="is_approve" readonly="1"/> - <field name="order_id" readonly="1"/> - <field name="counter" readonly="1"/> - <field name="approval_status" readonly="1"/> + <field name="description" attrs="{'readonly': [('approval_status', '=', 'approved')]}"/> </group> - </group> - <group> - <field name="description" attrs="{'readonly': [('approval_status', '=', 'approved')]}"/> - </group> - <notebook> - <page string="Invoices"> - <field name="due_line" attrs="{'readonly': [('is_approve', '=', True)]}"/> - </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> + <notebook> + <page string="Invoices"> + <field name="due_line" attrs="{'readonly': [('is_approve', '=', True)]}"/> + </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="due_extension_view_search" model="ir.ui.view"> + <field name="name">due.extension.search.view</field> <!-- Made the name more descriptive --> + <field name="model">due.extension</field> + <field name="arch" type="xml"> + <search string="Search Due Extension"> + <field name="number"/> + <field name="partner_id"/> + <field name="invoice_id"/> + <field name="order_id"/> + </search> + </field> + </record> <record id="due_extension_action" model="ir.actions.act_window"> <field name="name">Due Extension</field> diff --git a/indoteknik_custom/views/delivery_carrier.xml b/indoteknik_custom/views/delivery_carrier.xml index 5b2f2c32..ba01b8f2 100644 --- a/indoteknik_custom/views/delivery_carrier.xml +++ b/indoteknik_custom/views/delivery_carrier.xml @@ -9,6 +9,7 @@ <field name="company_id" position="after"> <field name="pic_name"/> <field name="pic_phone"/> + <field name="address"/> </field> </field> </record> diff --git a/indoteknik_custom/views/ir_sequence.xml b/indoteknik_custom/views/ir_sequence.xml index af07ba38..40ce135c 100644 --- a/indoteknik_custom/views/ir_sequence.xml +++ b/indoteknik_custom/views/ir_sequence.xml @@ -20,6 +20,16 @@ <field name="number_next">1</field> <field name="number_increment">1</field> </record> + + <record id="sequence_logbook_bill" model="ir.sequence"> + <field name="name">Logbook Bill</field> + <field name="code">report.logbook.bill</field> + <field name="active">TRUE</field> + <field name="prefix">LSB/%(year)s/</field> + <field name="padding">5</field> + <field name="number_next">1</field> + <field name="number_increment">1</field> + </record> <record id="sequence_stock_picking_code" model="ir.sequence"> <field name="name">Stock Picking Code</field> diff --git a/indoteknik_custom/views/logbook_bill.xml b/indoteknik_custom/views/logbook_bill.xml new file mode 100644 index 00000000..25f1d704 --- /dev/null +++ b/indoteknik_custom/views/logbook_bill.xml @@ -0,0 +1,55 @@ +<?xml version="1.0" encoding="utf-8" ?> +<odoo> + <record id="view_logbook_bill_form" model="ir.ui.view"> + <field name="name">Logbook Bill</field> + <field name="model">logbook.bill</field> + <field name="arch" type="xml"> + <form> + <sheet> + <field name="name" invisible="1"/> + <field + name="logbook_bill_line" + mode="tree" + > + <tree editable="bottom"> + <control> + <create name="add_logbook_bill_line_control" string="Add a logbook"/> + </control> + <field name="name" required="1"/> + <field name="partner_id" readonly="1"/> + <field name="purchase_id" readonly="1"/> + <field name="invoice"/> + <field name="faktur_pajak"/> + <field name="surat_jalan"/> + <field name="proforma_invoice"/> + <field name="date_approve" readonly="1"/> + <field name="note"/> + <field name="note_finance"/> + </tree> + </field> + </sheet> + <footer> + <button name="create_logbook_bill" string="Submit" type="object" default_focus="1" class="oe_highlight"/> + <button string="Cancel" class="btn btn-secondary" special="cancel" /> + </footer> + </form> + </field> + </record> + + <record id="action_logbook_bill" model="ir.actions.act_window"> + <field name="name">Logbook Bill</field> + <field name="res_model">logbook.bill</field> + <field name="type">ir.actions.act_window</field> + <field name="view_mode">form</field> + <field name="view_id" ref="view_logbook_bill_form"/> + <field name="target">new</field> + </record> + + <menuitem + action="action_logbook_bill" + id="logbook_bill" + parent="stock.menu_stock_warehouse_mgmt" + name="Logbook Bill" + sequence="1" + /> +</odoo>
\ No newline at end of file diff --git a/indoteknik_custom/views/mail_template_efaktur.xml b/indoteknik_custom/views/mail_template_efaktur.xml new file mode 100644 index 00000000..ca0ea427 --- /dev/null +++ b/indoteknik_custom/views/mail_template_efaktur.xml @@ -0,0 +1,26 @@ +<?xml version="1.0" ?> +<odoo> + <data> + <record id="mail_template_efaktur_document" model="mail.template"> + <field name="name">Invoice: Send mail efaktur document</field> + <field name="model_id" ref="model_account_move" /> + <field name="subject">Your Invoice ${object.name}</field> + <field name="email_from">sales@indoteknik.com</field> + <field name="email_to">${object.partner_id.email|safe}</field> + <field name="body_html" type="html"> + <p>Dengan Hormat Bpk/Ibu ${object.partner_id.name},</p> + <p>Terlampir Faktur Pajak atas Invoice ${object.name}.</p> + <p><strong>Keterangan:</strong></p> + <p>Mohon dicek langsung faktur pajak terlampir, terutama informasi nomor NPWP dan alamat NPWP serta nama pembelian barang. Jika ada yang tidak sesuai, mohon segera menginformasikan kepada kami paling lambat 1 (satu) minggu dari tanggal email ini. Revisi faktur pajak tidak dapat kami proses apabila sudah melewati 1 (satu) minggu. Harap maklum.</p> + <p>Mohon balas email ini jika sudah menerima, terima kasih.</p> + <p>Best Regards,<br /> + PT. Indoteknik Dotcom Gemilang<br /> + Jl. Bandengan Utara 85A No. 8-9 Penjaringan.<br /> + Kec. Penjaringan, Jakarta Utara - DKI Jakarta<br /> + Telp: 021-2933 8828 / 29 | GSM: 0813 9000 7430 / 31<br /> + Email: sales@indoteknik.com | Whatsapp: 0812 8080 622</p> + </field> + <field name="auto_delete" eval="True" /> + </record> + </data> +</odoo> diff --git a/indoteknik_custom/views/purchase_order.xml b/indoteknik_custom/views/purchase_order.xml index 08ff7e84..08ab8691 100755 --- a/indoteknik_custom/views/purchase_order.xml +++ b/indoteknik_custom/views/purchase_order.xml @@ -92,6 +92,7 @@ <field name="status_paid_cbd"/> <field name="from_apo"/> <field name="approval_edit_line"/> + <field name="logbook_bill_id"/> </field> <field name="order_line" position="attributes"> @@ -136,6 +137,8 @@ <field name="responsible_ids" widget="many2many_tags" optional="hide"/> <field name="matches_so" widget="many2many_tags" optional="hide"/> <field name="is_create_uangmuka" optional="hide"/> + <field name="logbook_bill_id" optional="hide"/> + <field name="status_printed" optional="hide"/> </field> </field> </record> @@ -154,6 +157,8 @@ <field name="is_create_uangmuka" optional="hide"/> <field name="responsible_ids" widget="many2many_tags" optional="hide"/> <field name="matches_so" widget="many2many_tags" optional="hide"/> + <field name="logbook_bill_id" optional="hide"/> + <field name="status_printed" optional="hide"/> </field> </field> </record> diff --git a/indoteknik_custom/views/purchase_pricelist.xml b/indoteknik_custom/views/purchase_pricelist.xml index 05a6930b..1ede6854 100755 --- a/indoteknik_custom/views/purchase_pricelist.xml +++ b/indoteknik_custom/views/purchase_pricelist.xml @@ -41,12 +41,12 @@ </group> <group string="System"> <field name="system_price"/> - <field name="taxes_system_id"/> + <field name="taxes_system_id" domain="[('type_tax_use','=','purchase')]"/> <field name="system_last_update"/> </group> <group string="Human"> <field name="product_price"/> - <field name="taxes_product_id"/> + <field name="taxes_product_id" domain="[('type_tax_use','=','purchase')]"/> <field name="human_last_update"/> </group> </group> diff --git a/indoteknik_custom/views/report_logbook_bill.xml b/indoteknik_custom/views/report_logbook_bill.xml new file mode 100644 index 00000000..fc461400 --- /dev/null +++ b/indoteknik_custom/views/report_logbook_bill.xml @@ -0,0 +1,97 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<odoo> + <record id="report_logbook_bill_tree" model="ir.ui.view"> + <field name="name">report.logbook.bill.tree</field> + <field name="model">report.logbook.bill</field> + <field name="arch" type="xml"> + <tree create="0" delete="0"> + <field name="name"/> + <field name="approve_by"/> + <field name="created_by"/> + <field name="date"/> + <field name="date_approve"/> + <field name="approve_by_finance"/> + <field name="state"/> + <field name="state_pengajuan"/> + </tree> + </field> + </record> + + <record id="report_logbook_bill_line_tree" model="ir.ui.view"> + <field name="name">report.logbook.bill.line.tree</field> + <field name="model">report.logbook.bill.line</field> + <field name="arch" type="xml"> + <tree editable="bottom"> + <field name="name"/> + <field name="partner_id"/> + <field name="purchase_id"/> + <field name="invoice"/> + <field name="faktur_pajak"/> + <field name="surat_jalan"/> + <field name="proforma_invoice"/> + <field name="date_approve"/> + <field name="grand_total"/> + <field name="not_exist"/> + <field name="note"/> + <field name="note_finance"/> + </tree> + </field> + </record> + + <record id="report_logbook_bill_form" model="ir.ui.view"> + <field name="name">report.logbook.bill.form</field> + <field name="model">report.logbook.bill</field> + <field name="arch" type="xml"> + <form> + <header> + <button name="approve" + string="Validate" + type="object" + /> + </header> + <sheet string="Report logbook Bill"> + <div class="oe_button_box" name="button_box"/> + <group> + <group> + <field name="name" readonly="1"/> + <field name="date" readonly="1"/> + <field name="date_approve" readonly="1"/> + <field name="state_pengajuan" readonly="1"/> + <field name="pengajuan_by" readonly="1"/> + <field name="date_pengajuan" readonly="1"/> + </group> + <group> + <field name="approve_by_finance" readonly="1"/> + <field name="state" readonly="1"/> + <field name="created_by" readonly="1"/> + <field name="approve_by" readonly="1"/> + <field name="count_line" readonly="1"/> + </group> + </group> + <notebook> + <page string="Line"> + <field name="report_logbook_bill_line"/> + </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="report_logbook_bill_action" model="ir.actions.act_window"> + <field name="name">Report Logbook Bill</field> + <field name="type">ir.actions.act_window</field> + <field name="res_model">report.logbook.bill</field> + <field name="view_mode">tree,form</field> + </record> + + <menuitem id="menu_report_logbook_bill" + name="Report Logbook Bill" + action="report_logbook_bill_action" + parent="account.menu_finance_reports" + sequence="200"/> +</odoo>
\ No newline at end of file diff --git a/indoteknik_custom/views/sale_order.xml b/indoteknik_custom/views/sale_order.xml index 42a101d0..3eec6d3e 100755 --- a/indoteknik_custom/views/sale_order.xml +++ b/indoteknik_custom/views/sale_order.xml @@ -49,10 +49,11 @@ </field> <field name="user_id" position="after"> <field name="helper_by_id" readonly="1"/> - <!-- <field name="compute_fullfillment"/> --> + <field name="compute_fullfillment"/> </field> <field name="tag_ids" position="after"> <field name="eta_date" readonly="1"/> + <field name="flash_sale"/> </field> <field name="analytic_account_id" position="after"> <field name="customer_type" required="1"/> @@ -140,6 +141,7 @@ <field name="carrier_id"/> <field name="estimated_arrival_days"/> <field name="picking_iu_id"/> + <field name="note_ekspedisi"/> </field> <field name="carrier_id" position="attributes"> <attribute name="attrs"> @@ -187,9 +189,9 @@ <page string="Matches PO" name="page_matches_po" invisible="1"> <field name="order_sales_match_line" readonly="1"/> </page> - <!-- <page string="Fullfillment" name="page_sale_order_fullfillment"> + <page string="Fullfillment" name="page_sale_order_fullfillment"> <field name="fullfillment_line" readonly="1"/> - </page> --> + </page> </page> </field> </record> @@ -296,7 +298,7 @@ </record> </data> - <!-- <data> + <data> <record id="sales_order_fullfillmet_tree" model="ir.ui.view"> <field name="name">sales.order.fullfillment.tree</field> <field name="model">sales.order.fullfillment</field> @@ -309,7 +311,17 @@ </tree> </field> </record> - </data> --> + </data> + + <data> + <record id="sale_order_multi_create_uangmuka_ir_actions_server" model="ir.actions.server"> + <field name="name">Uang Muka</field> + <field name="model_id" ref="sale.model_sale_order"/> + <field name="binding_model_id" ref="sale.model_sale_order"/> + <field name="state">code</field> + <field name="code">action = records.open_form_multi_create_uang_muka()</field> + </record> + </data> <data> <record id="mail_template_sale_order_notification_to_salesperson" model="mail.template"> @@ -332,12 +344,6 @@ <span></span> </td> </tr> - - <tr> - <td colspan="2" style="text-align:center;"> - <hr width="100%" style="background-color:rgb(204,204,204);border:medium none;clear:both;display:block;font-size:0px;min-height:1px;line-height:0; margin: 16px 0px 16px 0px;" /> - </td> - </tr> </table> </td> </tr> @@ -345,10 +351,28 @@ <tr> <td align="center" style="min-width: 590px;"> <table border="0" cellpadding="0" cellspacing="0" width="590" style="min-width: 590px; background-color: white; padding: 0px 8px 0px 8px; border-collapse:separate;"> - <tr><td style="padding-bottom: 24px;">Dear ${object.user_id.name},</td></tr> - - <tr><td style="padding-bottom: 16px;">Terdapat pesanan ${object.name} dari ${object.partner_id.main_parent_id.name} untuk site ${object.partner_shipping_id.site_id.name | safe} dengan total pembelian ${object.grand_total}</td></tr> - + <tr><td style="padding-bottom: 24px;">Dear ${salesperson_name},</td></tr> + + <tr><td style="padding-bottom: 16px;">Terdapat pesanan dari BP ${business_partner} untuk site ${site} dengan total belanja ${sum_total_amount} dari list SO dibawah ini:</td></tr> + + <tr> + <td> + <table border="1" cellpadding="5" cellspacing="0"> + <thead> + <tr> + <th>Nama Pesanan</th> + <th>Nama Perusahaan Induk</th> + <th>Nama Situs</th> + <th>Total Pembelian</th> + </tr> + </thead> + <tbody> + ${table_content} + </tbody> + </table> + </td> + </tr> + <tr> <td style="text-align:center;"> <hr width="100%" diff --git a/indoteknik_custom/views/sale_order_multi_uangmuka_penjualan.xml b/indoteknik_custom/views/sale_order_multi_uangmuka_penjualan.xml new file mode 100644 index 00000000..a72aed87 --- /dev/null +++ b/indoteknik_custom/views/sale_order_multi_uangmuka_penjualan.xml @@ -0,0 +1,36 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<odoo> + <data> + <record id="view_sale_order_multi_create_uangmuka_form" model="ir.ui.view"> + <field name="name">Sale Order Multi Create Uangmuka</field> + <field name="model">sale.order.multi_uangmuka_penjualan</field> + <field name="arch" type="xml"> + <form string="Invoice Sales Order"> + <p class="oe_grey"> + Pembuatan semi otomatis Uang Muka Penjualan, mohon dicek kembali + </p> + <group> + <field name="pay_amt"/> + <field name="ongkir_amt"/> + <field name="selisih_amt"/> + <field name="account_id" domain="[('name', 'ilike', 'intransit')]"/> + <field name="total_amt" readonly="1"/> + </group> + <footer> + <button name="create_uangmukapenjualanselected" string="Create Uang Muka" type="object" default_focus="1" class="oe_highlight"/> + <button string="Cancel" class="btn btn-secondary" special="cancel" /> + </footer> + </form> + </field> + </record> + + <record id="action_sale_order_multi_uangmuka" model="ir.actions.act_window"> + <field name="name">Sale Order Multi Create Uangmuka</field> + <field name="res_model">sale.order.multi_uangmuka_penjualan</field> + <field name="type">ir.actions.act_window</field> + <field name="view_mode">form</field> + <field name="view_id" ref="view_sale_order_multi_create_uangmuka_form"/> + <field name="target">new</field> + </record> + </data> +</odoo>
\ No newline at end of file |
