diff options
| author | it-fixcomart <it@fixcomart.co.id> | 2025-01-15 15:43:42 +0700 |
|---|---|---|
| committer | it-fixcomart <it@fixcomart.co.id> | 2025-01-15 15:43:42 +0700 |
| commit | be1ee2092fef86e79932206cc48d5a146107ac32 (patch) | |
| tree | e54a8c6ffda996f212ab1c2d03b27a32bab8ba89 /indoteknik_api | |
| parent | 8b2897d9c72eb67382221d320d488543aea08323 (diff) | |
| parent | e4ec9406cd0903db59cfed34781da55a2dba4ca3 (diff) | |
Merge branch 'odoo-production' into iman/switch-account
Diffstat (limited to 'indoteknik_api')
| -rw-r--r-- | indoteknik_api/controllers/api_v1/flash_sale.py | 2 | ||||
| -rw-r--r-- | indoteknik_api/controllers/api_v1/invoice.py | 25 | ||||
| -rw-r--r-- | indoteknik_api/controllers/api_v1/partner.py | 341 | ||||
| -rw-r--r-- | indoteknik_api/controllers/api_v1/sale_order.py | 6 | ||||
| -rw-r--r-- | indoteknik_api/controllers/api_v1/state.py | 6 | ||||
| -rw-r--r-- | indoteknik_api/controllers/api_v1/user.py | 14 | ||||
| -rw-r--r-- | indoteknik_api/controllers/controller.py | 30 | ||||
| -rw-r--r-- | indoteknik_api/models/__init__.py | 1 | ||||
| -rw-r--r-- | indoteknik_api/models/account_move.py | 5 | ||||
| -rw-r--r-- | indoteknik_api/models/product_product.py | 12 | ||||
| -rw-r--r-- | indoteknik_api/models/product_template.py | 6 | ||||
| -rw-r--r-- | indoteknik_api/models/res_partner.py | 170 | ||||
| -rw-r--r-- | indoteknik_api/models/res_users.py | 17 | ||||
| -rw-r--r-- | indoteknik_api/models/sale_order.py | 7 |
14 files changed, 623 insertions, 19 deletions
diff --git a/indoteknik_api/controllers/api_v1/flash_sale.py b/indoteknik_api/controllers/api_v1/flash_sale.py index 00b1f2e0..6c4ad8c0 100644 --- a/indoteknik_api/controllers/api_v1/flash_sale.py +++ b/indoteknik_api/controllers/api_v1/flash_sale.py @@ -20,6 +20,7 @@ class FlashSale(controller.Controller): query = [ ('pricelist_id', '=', pricelist.id) ] + formatted_end_date = pricelist.end_date.strftime('%Y-%m-%dT%H:%M:%S.%f')[:-3] + 'Z' if pricelist.end_date else None data.append({ 'pricelist_id': pricelist.id, 'option': pricelist.flashsale_option, @@ -29,6 +30,7 @@ class FlashSale(controller.Controller): 'banner_mobile': request.env['ir.attachment'].api_image('product.pricelist', 'banner_mobile', pricelist.id), 'banner_top': request.env['ir.attachment'].api_image('product.pricelist', 'banner_top', pricelist.id), 'duration': pricelist._remaining_time_in_second(), + 'end_date': formatted_end_date, 'product_total': request.env['product.pricelist.item'].search_count(query), }) return self.response(data) diff --git a/indoteknik_api/controllers/api_v1/invoice.py b/indoteknik_api/controllers/api_v1/invoice.py index 4937e8dd..4bd3746c 100644 --- a/indoteknik_api/controllers/api_v1/invoice.py +++ b/indoteknik_api/controllers/api_v1/invoice.py @@ -1,7 +1,7 @@ from .. import controller from odoo import http from odoo.http import request - +from odoo import fields class Invoice(controller.Controller): PREFIX = '/api/v1/' @@ -15,6 +15,7 @@ class Invoice(controller.Controller): 'name': [], 'limit': ['default:0', 'number'], 'offset': ['default:0', 'number'], + 'status': [], }) limit = params['value']['limit'] offset = params['value']['offset'] @@ -27,6 +28,11 @@ class Invoice(controller.Controller): ('state', '=', 'posted'), ('partner_id', 'in', partner_child_ids) ] + domain_orders = [ + ('invoice_status', '!=', 'invoiced'), + ('state', '=', 'sale'), + ('partner_id', 'in', partner_child_ids) + ] if params['value']['name']: name = params['value']['name'].replace(' ', '%') domain += [ @@ -34,10 +40,25 @@ class Invoice(controller.Controller): ('name', 'ilike', '%'+ name +'%'), ('ref', 'ilike', '%'+ name +'%') ] + if params['value']['status']: + if params['value']['status'] == '1': + domain += [('payment_state', '=', 'not_paid'), ('invoice_date_due', '<', fields.Date.today())] + elif params['value']['status'] == '2': + domain += [('payment_state', '=', 'not_paid'), ('invoice_date_due', '>', fields.Date.today())] + elif params['value']['status'] == '3': + domain += [('payment_state', '=', 'paid')] + elif params['value']['status'] == '0': + domain = domain + elif params['value']['status'] == '4': + domain += [('payment_state', '=', 'not_paid')] + invoices = request.env['account.move'].search(domain, offset=offset, limit=limit) + sale_orders = request.env['sale.order'].search(domain_orders, offset=offset, limit=limit) data = { 'invoice_total': request.env['account.move'].search_count(domain), - 'invoices': [request.env['account.move'].api_v1_single_response(x) for x in invoices] + 'invoices': [request.env['account.move'].api_v1_single_response(x) for x in invoices], + 'sale_order_total': request.env['sale.order'].search_count(domain_orders), + 'sale_orders': [request.env['sale.order'].api_v1_single_response(x) for x in sale_orders] } return self.response(data) diff --git a/indoteknik_api/controllers/api_v1/partner.py b/indoteknik_api/controllers/api_v1/partner.py index f9ec7101..307165b3 100644 --- a/indoteknik_api/controllers/api_v1/partner.py +++ b/indoteknik_api/controllers/api_v1/partner.py @@ -1,7 +1,10 @@ from .. import controller from odoo import http from odoo.http import request - +from odoo import fields +import json +import base64 +import mimetypes class Partner(controller.Controller): _name = 'res.partner' @@ -135,6 +138,8 @@ class Partner(controller.Controller): 'npwp': [], 'alamat_lengkap_text': [], 'street': [], + 'email': [], + 'mobile': [] }) id_user = self.get_request_params(kw, { 'id_user': ['number'] @@ -213,6 +218,32 @@ class Partner(controller.Controller): }) return self.response(data) + + @http.route(prefix + 'partner/payment_term', auth='public', methods=['GET', 'OPTIONS']) + @controller.Controller.must_authorized() + def get_partner_payment_term(self): + partner_industry = request.env['account.payment.term'].search([]) + data = [] + for industry in partner_industry: + if 'tempo' in industry.name.lower(): + data.append({ + 'id': industry.id, + 'name': industry.name + }) + + return self.response(data) + + @http.route(prefix + 'partner/detail-tempo/<id>', auth='public', methods=['GET', 'OPTIONS']) + @controller.Controller.must_authorized() + def get_partner_detail_tempo(self, **kw): + params = self.get_request_params(kw, { + 'id': ['required', 'number'] + }) + pengajuan_tempo = request.env['user.pengajuan.tempo'].search([('name_tempo', '=', params['value']['id'])], limit=1) + if not pengajuan_tempo: + return self.response(code=404, description='pengajuan tempo not found') + pengajuan_tempo = request.env['res.partner'].api_single_response(pengajuan_tempo) + return self.response(pengajuan_tempo) @http.route(prefix + 'check/<partner_id>/tempo', auth='public', methods=['GET', 'OPTIONS']) @controller.Controller.must_authorized() @@ -227,18 +258,318 @@ class Partner(controller.Controller): if any(line.days == 0 for line in partner.property_payment_term_id.line_ids): return self.response(code=402, description='Partner not tempo') - - result_tempo = sum(m.amount_total_signed for m in request.env['account.move'].search([('partner_id', '=', partner.id), ('payment_state', '=', 'not_paid'), ('state', '=', 'posted')])) - + + domain_result_tempo = [('partner_id', '=', partner.id), ('payment_state', '=', 'not_paid'), ('state', '=', 'posted')] + domain_result_jatuh_tempo = [('partner_id', '=', partner.id), ('payment_state', '=', 'not_paid'), ('state', '=', 'posted'), ('invoice_date_due', '<', fields.Date.today())] + domain_orders = [('partner_id', '=', partner.id), ('invoice_status', '!=', 'invoiced'), ('state', '=', 'sale')] + + result_tempo = sum(m.amount_total_signed for m in request.env['account.move'].search(domain_result_tempo)) + result_tempo_total = request.env['account.move'].search_count(domain_result_tempo) + result_jatuh_tempo = sum(m.amount_total_signed for m in request.env['account.move'].search(domain_result_jatuh_tempo)) + result_jatuh_tempo_total = request.env['account.move'].search_count(domain_result_jatuh_tempo) + orders = request.env['sale.order'].search(domain_orders) + orders_total = request.env['sale.order'].search_count(domain_orders) + + total_amount = sum(order.amount_total for order in orders) + remaining_limit = partner.blocking_stage - result_tempo if partner.active_limit else None data = { 'name': partner.name, + 'payment_term': partner.property_payment_term_id.name, 'amount_due': result_tempo, + 'amount_due_total': result_tempo_total, + 'amount_jatuh_tempo_total': result_jatuh_tempo_total, + 'amount_jatuh_tempo': result_jatuh_tempo, + 'amount_due_sale': total_amount, + 'amount_due_sale_total': orders_total, 'remaining_limit': remaining_limit } - + + return self.response(data) + + @http.route(prefix + 'check/<partner_id>/tempo_progress', auth='public', methods=['GET', 'OPTIONS']) + @controller.Controller.must_authorized() + def get_check_tempo_partner_progres(self, **kw): + partner_id = int(kw.get('partner_id')) + partner = request.env['res.partner'].search([('id', '=', partner_id)], limit=1) + pengajuan_tempo = request.env['user.pengajuan.tempo'].search([('name_tempo', '=', partner.id)], limit=1) + if not pengajuan_tempo: + return self.response(code=404, description='Partner not found') + + data = True if pengajuan_tempo.id else False return self.response(data) + @http.route(prefix + 'partner/pengajuan_tempo', auth='public', methods=['POST'], csrf=False) + @controller.Controller.must_authorized() + def write_pengajuan_tempo(self, **kw): + id = int(kw.get('partner_id')) + user_id = int(kw.get('user_id')) + tempo_request = True if kw.get('tempo_request') == 'true' else False + pengajuan_tempo = request.env['user.pengajuan.tempo'].search([('name_tempo', '=', user_id)], limit=1) + user = request.env['res.partner'].search([('id', '=', user_id)], limit=1) + company_name = kw.get('name', pengajuan_tempo.name_tempo.name) + partner_id = request.env['res.partner'].search([('name', 'like', company_name)], limit=1) + user_account = self.get_user_by_email(user.email) + params = self.get_request_params(kw, { + + # informasi perusahaan + # 'name': ['required', 'alias:name_tempo'], + 'industryId': ['alias:industry_id_tempo'], + 'street': ['alias:street_tempo'], + 'state': ['alias:state_id_tempo'], + 'city': ['alias:city_id_tempo'], + 'district': ['alias:district_id_tempo'], + 'subDistrict': ['alias:subDistrict_id_tempo'], + 'zip': ['alias:zip_tempo'], + 'mobile': ['alias:mobile_tempo'], + 'bankName': ['alias:bank_name_tempo'], + 'accountName': ['alias:account_name_tempo'], + 'accountNumber': ['alias:account_number_tempo'], + 'website': ['alias:website_tempo'], + 'estimasi': ['alias:estimasi_tempo'], + 'portal': ['alias:portal'], + 'bersedia': ['alias:bersedia'], + 'tempoDuration': ['alias:tempo_duration'], + 'tempoLimit': ['alias:tempo_limit'], + + # informasi perusahaan + 'direkturTittle': ['alias:direktur_tittle'], + 'direkturName': ['alias:direktur_name'], + 'direkturMobile': ['alias:direktur_mobile'], + 'direkturEmail': ['alias:direktur_email'], + 'purchasingTittle': ['alias:purchasing_tittle'], + 'purchasingName': ['alias:purchasing_name'], + 'purchasingMobile': ['alias:purchasing_mobile'], + 'purchasingEmail': ['alias:purchasing_email'], + 'financeTittle': ['alias:finance_tittle'], + 'financeName': ['alias:finance_name'], + 'financeMobile': ['alias:finance_mobile'], + 'financeEmail': ['alias:finance_email'], + + # Pengiriman + 'PICTittle': ['alias:pic_tittle'], + 'PICName': ['alias:pic_name'], + 'streetPengiriman': ['alias:street_pengiriman'], + 'statePengiriman': ['alias:state_id_pengiriman'], + 'cityPengiriman': ['alias:city_id_pengiriman'], + 'districtPengiriman': ['alias:district_id_pengiriman'], + 'subDistrictPengiriman': ['alias:subDistrict_id_pengiriman'], + 'zipPengiriman': ['alias:zip_pengiriman'], + 'invoicePicTittle': ['alias:invoice_pic_tittle'], + 'invoicePic': ['alias:invoice_pic'], + 'streetInvoice': ['alias:street_invoice'], + 'stateInvoice': ['alias:state_id_invoice'], + 'cityInvoice': ['alias:city_id_invoice'], + 'districtInvoice': ['alias:district_id_invoice'], + 'subDistrictInvoice': ['alias:subDistrict_id_invoice'], + 'zipInvoice': ['alias:zip_invoice'], + 'isSameAddrees':['alias:is_same_address'], + 'isSameAddreesStreet':['alias:is_same_address_street'], + }) + + # # Konversi nilai 'true' ke boolean True + # is_same_address = kw.get('isSameAddrees', 'false').lower() == 'true' + # is_same_address_street = kw.get('isSameAddreesStreet', 'false').lower() == 'true' + # + # # Tambahkan nilai yang dikonversi ke params + # if 'isSameAddress' in kw: + # params['value']['is_same_address'] = is_same_address + # if 'is_same_address_street' in kw: + # params['value']['is_same_address_street'] = is_same_address_street + + if not params['valid']: + return self.response(code=400, description=params) + if params['value']['portal']: + if params['value']['portal'] == 'ada': + params['value']['portal'] = True + else: + params['value']['portal'] = False + # Filter data baru yang dikirim (non-kosong, boolean False tetap masuk) + new_data = {key: value for key, value in params['value'].items() if value != ''} + + if pengajuan_tempo: + # Jika pengajuan_tempo sudah ada, hanya write data baru yang non-kosong + pengajuan_tempo.write(new_data) + else: + # Jika belum ada, buat record baru + pengajuan_tempo = request.env['user.pengajuan.tempo'].create(new_data) + pengajuan_tempo.partner_id = user_id + + if partner_id: + pengajuan_tempo.name_tempo = partner_id + + form_supplier_data = kw.get('formSupplier', False) + + if form_supplier_data: + try: + form_supplier_data = json.loads(form_supplier_data) + + supplier_ids_to_add = [] + for item in form_supplier_data: + supplier_name = item.get("supplier") + pic_name = item.get("pic") + phone = item.get("telepon") + tempo_duration = item.get("durasiTempo") + credit_limit = item.get("creditLimit") + + new_data = { + 'name_supplier': supplier_name, + 'pic_name': pic_name, + 'phone': phone, + 'tempo_duration': tempo_duration, + 'credit_limit': credit_limit, + } + new_supplier_data = request.env['user.pengajuan.tempo.line'].create(new_data) + + supplier_ids_to_add.append(new_supplier_data.id) + + pengajuan_tempo.write({'supplier_ids': [(6, 0, supplier_ids_to_add)]}) + + except json.JSONDecodeError: + return http.Response(status=400, json_body={'error': 'Invalid JSON format for formSupplier'}) + category_produk_ids = kw.get('categoryProduk', False) + category_ids = '' + if category_produk_ids: + category_ids = list(map(int, category_produk_ids.split(','))) + pengajuan_tempo.category_produk_ids = [(6, 0, category_ids)] + + tukar_invoice_input = kw.get('tukarInvoiceInput') + if tukar_invoice_input: + pengajuan_tempo.tukar_invoice = tukar_invoice_input + + tukar_invoice_input_pembayaran = kw.get('tukarInvoiceInputPembayaran') + if tukar_invoice_input_pembayaran: + pengajuan_tempo.jadwal_bayar = tukar_invoice_input_pembayaran + + dokumen_kirim = [ + 'Surat Tanda Terima Barang (STTB)', + 'Good Receipt (GR)', + 'Surat Terima Barang (STB)', + 'Lembar Penerimaan Barang (LPB)' + ] + + dokumen_kirim_barang_ids = kw.get('dokumenPengiriman') + dokumen_kirim_input = kw.get('dokumenKirimInput', '') + dokumen_kirim_barang_input = kw.get('dokumenPengirimanInput', '') + dokumen_kirim_barang = [] + + if dokumen_kirim_barang_ids: + dokumen_kirim_ids = list(map(int, dokumen_kirim_barang_ids.split(','))) + dokumen_kirim_barang = [dokumen_kirim[i] for i in dokumen_kirim_ids if 0 <= i < len(dokumen_kirim)] + if dokumen_kirim_input: + input_items = [item.strip() for item in dokumen_kirim_input.split(',')] + dokumen_kirim_barang.extend(item for item in input_items if item and item not in dokumen_kirim_barang) + pengajuan_tempo.dokumen_kirim_input = dokumen_kirim_input + if dokumen_kirim_barang: + pengajuan_tempo.dokumen_pengiriman = ', '.join(dokumen_kirim_barang) + if dokumen_kirim_barang_input: + pengajuan_tempo.dokumen_pengiriman_input = dokumen_kirim_barang_input + + dokumen = [ + 'Invoice Pembelian', + 'Surat Jalan', + 'Berita Acara Serah Terima (BAST)', + 'Faktur Pajak', + 'Good Receipt (GR)' + ] + + dokumen_invoice = kw.get('dokumenPengirimanInvoice', '') + if dokumen_invoice: + pengajuan_tempo.dokumen_invoice = dokumen_invoice + user_tempo_request = [] + if tempo_request: + user_tempo_request = request.env['user.pengajuan.tempo.request'].create({ + 'user_id': id, + 'pengajuan_tempo_id': pengajuan_tempo.id, + 'user_company_id': partner_id.id, + 'tempo_duration': pengajuan_tempo.tempo_duration.id, + 'tempo_limit': pengajuan_tempo.tempo_limit, + }) + + form_dokumen_data = kw.get('formDocs', False) + if form_dokumen_data: + try: + form_dokumen = json.loads(form_dokumen_data) + + for dokumen in form_dokumen: + if dokumen['details']['base64'] != '': + mimetype, _ = mimetypes.guess_type(dokumen['details']['name']) + mimetype = mimetype or 'application/octet-stream' + data = base64.b64decode(dokumen['details']['base64']) + sppkp_attachment = request.env['ir.attachment'].create({ + 'name': dokumen['details']['name'], + 'type': 'binary', + 'datas': base64.b64encode(data), + 'res_model': 'user.pengajuan.tempo', + 'res_id': pengajuan_tempo.id, + 'mimetype': mimetype + }) + + if dokumen['documentName'] == 'dokumenNib': + pengajuan_tempo.dokumen_nib = [(6, 0, [sppkp_attachment.id])] + + elif dokumen['documentName'] == 'dokumenSiup': + pengajuan_tempo.dokumen_siup = [(6, 0, [sppkp_attachment.id])] + + elif dokumen['documentName'] == 'dokumenTdp': + pengajuan_tempo.dokumen_tdp = [(6, 0, [sppkp_attachment.id])] + + elif dokumen['documentName'] == 'dokumenSkdp': + pengajuan_tempo.dokumen_skdp = [(6, 0, [sppkp_attachment.id])] + + elif dokumen['documentName'] == 'dokumenSkt': + pengajuan_tempo.dokumen_skt = [(6, 0, [sppkp_attachment.id])] + + elif dokumen['documentName'] == 'dokumenNpwp': + pengajuan_tempo.dokumen_npwp = [(6, 0, [sppkp_attachment.id])] + + elif dokumen['documentName'] == 'dokumenSppkp': + pengajuan_tempo.dokumen_sppkp = [(6, 0, [sppkp_attachment.id])] + + elif dokumen['documentName'] == 'dokumenAktaPerubahan': + pengajuan_tempo.dokumen_akta_perubahan = [(6, 0, [sppkp_attachment.id])] + + elif dokumen['documentName'] == 'dokumenKtpDirut': + pengajuan_tempo.dokumen_ktp_dirut = [(6, 0, [sppkp_attachment.id])] + + elif dokumen['documentName'] == 'dokumenAktaPendirian': + pengajuan_tempo.dokumen_akta_pendirian = [(6, 0, [sppkp_attachment.id])] + + elif dokumen['documentName'] == 'dokumenLaporanKeuangan': + pengajuan_tempo.dokumen_laporan_keuangan = [(6, 0, [sppkp_attachment.id])] + + elif dokumen['documentName'] == 'dokumenFotoKantor': + pengajuan_tempo.dokumen_foto_kantor = [(6, 0, [sppkp_attachment.id])] + + elif dokumen['documentName'] == 'dokumenTempatBekerja': + pengajuan_tempo.dokumen_tempat_bekerja = [(6, 0, [sppkp_attachment.id])] + + formatted_text = ''.join([' ' + char if char.isupper() and i != 0 else char for i, char in + enumerate(dokumen['documentName'])]) + teks = formatted_text.strip().title() + pengajuan_tempo.message_post(body=teks, attachment_ids=[sppkp_attachment.id]) + if tempo_request: + user_tempo_request.message_post(body=teks, attachment_ids=[sppkp_attachment.id]) + + + except json.JSONDecodeError: + return http.Response(status=400, json_body={'error': 'Invalid JSON format for formDokumen'}) + + if tempo_request: + # pengajuan_tempo.user_id = id + template = pengajuan_tempo.env.ref('indoteknik_custom.mail_template_res_user_company_request_tempo_review') + template.send_mail(pengajuan_tempo.id, force_send=True) + template2 = pengajuan_tempo.env.ref('indoteknik_custom.mail_template_res_user_company_new_tempo_to_sales') + template2.send_mail(pengajuan_tempo.id, force_send=True) + return self.response({ + 'id': pengajuan_tempo.id, + 'user_id': user_id, + }) + def get_user_by_email(self, email): + return request.env['res.users'].search([ + ('login', '=', email), + ('active', 'in', [True, False]) + ])
\ No newline at end of file diff --git a/indoteknik_api/controllers/api_v1/sale_order.py b/indoteknik_api/controllers/api_v1/sale_order.py index 3e182a2e..8b95ade8 100644 --- a/indoteknik_api/controllers/api_v1/sale_order.py +++ b/indoteknik_api/controllers/api_v1/sale_order.py @@ -150,7 +150,8 @@ class SaleOrder(controller.Controller): def partner_checkout_sale_order_by_id(self, **kw): params = self.get_request_params(kw, { 'partner_id': ['number'], - 'id': ['number'] + 'id': ['number'], + 'status': ['boolean'] }) if not params['valid']: return self.response(code=400, description=params) @@ -163,6 +164,9 @@ class SaleOrder(controller.Controller): data = {} sale_order = request.env['sale.order'].search(domain) if sale_order: + if 'status' in params['value']: + sale_order.is_continue_transaction = params['value']['status'] + if sale_order._requires_approval_margin_leader(): sale_order.approval_status = 'pengajuan2' elif sale_order._requires_approval_margin_manager(): diff --git a/indoteknik_api/controllers/api_v1/state.py b/indoteknik_api/controllers/api_v1/state.py index 598ef70b..958359a7 100644 --- a/indoteknik_api/controllers/api_v1/state.py +++ b/indoteknik_api/controllers/api_v1/state.py @@ -8,7 +8,11 @@ class District(controller.Controller): @http.route(prefix + 'state', auth='public', methods=['GET', 'OPTIONS']) @controller.Controller.must_authorized() def get_state(self, **kw): + tempo = kw.get('tempo') parameters = [] + if tempo == 'true': + parameters.append(('country_id', '=', 100)) + name = kw.get('name') if name: @@ -18,7 +22,7 @@ class District(controller.Controller): states = request.env['res.country.state'].search(parameters) data = [] for state in states: - data.append({ 'id': state.id, 'name': state.name }) + data.append({ 'id': state.id, 'name': state.name}) return self.response(data) diff --git a/indoteknik_api/controllers/api_v1/user.py b/indoteknik_api/controllers/api_v1/user.py index a94ba1f8..f651d9fa 100644 --- a/indoteknik_api/controllers/api_v1/user.py +++ b/indoteknik_api/controllers/api_v1/user.py @@ -403,6 +403,20 @@ class User(controller.Controller): 'user': self.response_with_token(user) }) + @http.route(prefix + 'user/<id>/after_request_tempo', auth='public', methods=['PUT', 'OPTIONS'], csrf=False) + @controller.Controller.must_authorized() + def update_user_tempo_after_request(self, **kw): + id = kw.get('id') + + user = request.env['res.users'].search([('id', '=', id)], limit=1) + if not user: + return self.response(code=404, description='User not found') + + + return self.response({ + 'user': self.response_with_token(user) + }) + @http.route(prefix + 'user/<id>/address', auth='public', methods=['GET', 'OPTIONS']) @controller.Controller.must_authorized() def get_user_address_by_id(self, **kw): diff --git a/indoteknik_api/controllers/controller.py b/indoteknik_api/controllers/controller.py index a34a2688..80f45074 100644 --- a/indoteknik_api/controllers/controller.py +++ b/indoteknik_api/controllers/controller.py @@ -4,6 +4,7 @@ import functools import io import json from array import array +from io import BytesIO import jwt from odoo import http @@ -11,6 +12,8 @@ from odoo.http import request from odoo.modules import get_module_resource from odoo.tools.config import config from PIL import Image +from PIL.WebPImagePlugin import Image +from PIL import features from pytz import timezone @@ -204,6 +207,8 @@ class Controller(http.Controller): if not variant: image = self.add_watermark_to_image(image, ratio, version) + # image = self.convert_to_webp(image) + response_headers = [ ('Content-Type', 'image/jpg'), ('Cache-Control', 'public, max-age=3600') @@ -214,6 +219,31 @@ class Controller(http.Controller): response_headers ) + def convert_to_webp(self, image_base64): + """Convert image from base64 to WebP format and return base64 WebP.""" + try: + print(f"Image base64 length: {len(image_base64)}") + + # Decode Base64 to Bytes + image_data = base64.b64decode(image_base64) + image = Image.open(BytesIO(image_data)) + + if image.format == "PNG" and image.mode != "RGBA": + image = image.convert("RGBA") + + # Convert to WebP + with BytesIO() as output: + image.save(output, format="WEBP", quality=85) + webp_data = output.getvalue() + + # Encode back to Base64 + return base64.b64encode(webp_data).decode('utf-8') + except Exception as e: + print(f"Error details: {e}") + # If conversion fails, return the original image + request.env.cr.rollback() # Rollback any transactions + return image_base64 + def add_watermark_to_image(self, image, ratio, version = '1'): if not image: return '' diff --git a/indoteknik_api/models/__init__.py b/indoteknik_api/models/__init__.py index 892d2657..8c85938c 100644 --- a/indoteknik_api/models/__init__.py +++ b/indoteknik_api/models/__init__.py @@ -9,3 +9,4 @@ from . import sale_order from . import x_manufactures from . import website_content from . import coupon_program +from . import res_partner diff --git a/indoteknik_api/models/account_move.py b/indoteknik_api/models/account_move.py index 23a7076c..645c157a 100644 --- a/indoteknik_api/models/account_move.py +++ b/indoteknik_api/models/account_move.py @@ -7,6 +7,7 @@ class AccountMove(models.Model): def api_v1_single_response(self, account_move, context=False): sale_order = self.env['sale.order'].search([('name', '=', account_move.invoice_origin), ('state', '=', 'done')], limit=1) + sale_order_v2 = self.env['sale.order'].search([('name', '=', account_move.invoice_origin)],limit=1) amount_residual = account_move.amount_residual if sale_order.payment_status == 'settlement' or sale_order.payment_status == 'capture': amount_residual = 0 @@ -21,6 +22,9 @@ class AccountMove(models.Model): 'amount_residual': amount_residual, 'invoice_date': account_move.invoice_date.strftime('%d/%m/%Y') or '', 'efaktur': True if account_move.efaktur_document else False, + 'invoice_date_due': account_move.invoice_date_due.strftime('%d/%m/%Y') or '-', + 'sales_order': account_move.invoice_origin, + 'sales_order_id': sale_order_v2.id, } if isinstance(object, datetime.date): data['invoice_date'] = account_move.invoice_date.strftime('%d/%m/%Y') @@ -35,7 +39,6 @@ class AccountMove(models.Model): 'sales': account_move.invoice_user_id.name, 'amount_total': account_move.amount_total, 'amount_residual': amount_residual, - 'invoice_date_due': account_move.invoice_date_due.strftime('%d/%m/%Y') or '', 'customer': res_users.api_address_response(account_move.partner_id), 'products': [], } diff --git a/indoteknik_api/models/product_product.py b/indoteknik_api/models/product_product.py index f8869c7d..10922186 100644 --- a/indoteknik_api/models/product_product.py +++ b/indoteknik_api/models/product_product.py @@ -139,39 +139,39 @@ class ProductProduct(models.Model): return retValue def _get_website_price_exclude_tax(self): - default_divide_tax = float(1.11) + default_divide_tax = float(1.12) price_incl = self._get_website_price_include_tax() res = price_incl / default_divide_tax return math.floor(res) def _v2_get_website_price_exclude_tax(self): - default_divide_tax = float(1.11) + default_divide_tax = float(1.12) price_incl = self._v2_get_website_price_include_tax() res = price_incl / default_divide_tax return math.floor(res) def _get_website_price_after_disc_and_tax(self): - default_divide_tax = float(1.11) + default_divide_tax = float(1.12) price_after_disc = self._get_website_price_after_disc() res = price_after_disc / default_divide_tax res = math.ceil(res) return res def _v2_get_website_price_after_disc_and_tax(self): - default_divide_tax = float(1.11) + default_divide_tax = float(1.12) price_after_disc = self._v2_get_website_price_after_disc() res = price_after_disc / default_divide_tax res = math.ceil(res) return res def _get_website_tax(self): - default_percent_tax = float(11) + default_percent_tax = float(12) price_after_disc = self._get_website_price_after_disc_and_tax() res = price_after_disc * default_percent_tax / 100 return math.floor(res) def _v2_get_website_tax(self): - default_percent_tax = float(11) + default_percent_tax = float(12) price_after_disc = self._v2_get_website_price_after_disc_and_tax() res = price_after_disc * default_percent_tax / 100 return math.floor(res) diff --git a/indoteknik_api/models/product_template.py b/indoteknik_api/models/product_template.py index 75899624..e46e44d3 100644 --- a/indoteknik_api/models/product_template.py +++ b/indoteknik_api/models/product_template.py @@ -7,6 +7,11 @@ class ProductTemplate(models.Model): def api_single_response(self, product_template, with_detail=''): product_pricelist_default_discount_id = self.env['ir.config_parameter'].get_param('product.pricelist.default_discount_id') product_pricelist_default_discount_id = int(product_pricelist_default_discount_id) + voucher = self.get_voucher_pastihemat(product_template.x_manufacture.id) + newVoucherPastiHemat = {"min_purchase": voucher.min_purchase_amount or 0, + "discount_type": voucher.discount_type or '', + "discount_amount": voucher.discount_amount or 0, + "max_discount": voucher.max_discount_amount or 0,} data = { 'id': product_template.id, 'image': self.env['ir.attachment'].api_image('product.template', 'image_128', product_template.id), @@ -18,6 +23,7 @@ class ProductTemplate(models.Model): 'weight': product_template.weight, 'manufacture': self.api_manufacture(product_template), 'categories': self.api_categories(product_template), + "newVoucherPastiHemat": newVoucherPastiHemat } if with_detail != '': diff --git a/indoteknik_api/models/res_partner.py b/indoteknik_api/models/res_partner.py new file mode 100644 index 00000000..0e09fbc6 --- /dev/null +++ b/indoteknik_api/models/res_partner.py @@ -0,0 +1,170 @@ +from odoo import models +import json +import base64 + +class ResPartner(models.Model): + _inherit = 'res.partner' + + def api_single_response(self, pengajuan_tempo, with_detail=''): + config = self.env['ir.config_parameter'] + + partner = pengajuan_tempo.partner_id + + dokumen_kirim = [ + ['Surat Tanda Terima Barang (STTB)', '0'], + ['Good Receipt (GR)', '1'], + ['Surat Terima Barang (STB)', '2'], + ['Lembar Penerimaan Barang (LPB)', '3'] + ] + dokumen_pengiriman = [] + if pengajuan_tempo.dokumen_pengiriman : + pengajuan_tempo_dokumen_pengiriman = pengajuan_tempo.dokumen_pengiriman + mapping_dokumen = {item[0]: item[1] for item in dokumen_kirim} + dokumen_pengiriman_list = [dokumen.strip() for dokumen in pengajuan_tempo_dokumen_pengiriman.split(',')] + dokumen_pengiriman = [mapping_dokumen.get(dokumen, '4') for dokumen in dokumen_pengiriman_list] + data = { + 'name' : pengajuan_tempo.name_tempo.name, + 'industry_id' : pengajuan_tempo.industry_id_tempo.id, + 'street' : pengajuan_tempo.street_tempo, + 'state' : pengajuan_tempo.state_id_tempo.id, + 'city' : pengajuan_tempo.city_id_tempo.id, + 'district' : pengajuan_tempo.district_id_tempo.id, + 'subDistrict' : pengajuan_tempo.subDistrict_id_tempo.id, + 'zip' : pengajuan_tempo.zip_tempo, + 'mobile' : pengajuan_tempo.mobile_tempo, + 'bank_name' : pengajuan_tempo.bank_name_tempo, + 'account_name' : pengajuan_tempo.account_name_tempo, + 'account_number' : pengajuan_tempo.account_number_tempo, + 'website' : pengajuan_tempo.website_tempo if pengajuan_tempo.website_tempo else '', + 'estimasi' : pengajuan_tempo.estimasi_tempo, + 'bersedia' : pengajuan_tempo.bersedia, + 'portal' : 'ada' if pengajuan_tempo.portal else 'tidak', + 'tempo_duration' : pengajuan_tempo.tempo_duration.id, + 'tempo_limit' : pengajuan_tempo.tempo_limit, + 'category_produk': ','.join([str(cat.id) for cat in pengajuan_tempo.category_produk_ids]) if pengajuan_tempo.category_produk_ids else '', + + # Kontak Perusahaan + 'direktur_tittle': pengajuan_tempo.direktur_tittle if pengajuan_tempo.direktur_tittle else '', + 'direktur_name' : pengajuan_tempo.direktur_name if pengajuan_tempo.direktur_name else '', + 'direktur_mobile' : pengajuan_tempo.direktur_mobile if pengajuan_tempo.direktur_mobile else '', + 'direktur_email' : pengajuan_tempo.direktur_email if pengajuan_tempo.direktur_email else '', + 'purchasing_tittle': pengajuan_tempo.purchasing_tittle if pengajuan_tempo.purchasing_tittle else '', + 'purchasing_name' : pengajuan_tempo.purchasing_name if pengajuan_tempo.purchasing_name else '', + 'purchasing_mobile' : pengajuan_tempo.purchasing_mobile if pengajuan_tempo.purchasing_mobile else '', + 'purchasing_email' : pengajuan_tempo.purchasing_email if pengajuan_tempo.purchasing_email else '', + 'finance_tittle': pengajuan_tempo.finance_tittle if pengajuan_tempo.finance_tittle else '', + 'finance_name' : pengajuan_tempo.finance_name if pengajuan_tempo.finance_name else '', + 'finance_mobile' : pengajuan_tempo.finance_mobile if pengajuan_tempo.finance_mobile else '', + 'finance_email' : pengajuan_tempo.finance_email if pengajuan_tempo.finance_email else '', + + # Pengiriman + 'PIC_tittle' : pengajuan_tempo.pic_tittle if pengajuan_tempo.pic_tittle else '', + 'PIC_name' : pengajuan_tempo.pic_name if pengajuan_tempo.pic_name else '', + 'street_pengiriman' : pengajuan_tempo.street_pengiriman if pengajuan_tempo.street_pengiriman else '', + 'state_pengiriman' : pengajuan_tempo.state_id_pengiriman.id if pengajuan_tempo.state_id_pengiriman else '', + 'city_pengiriman' : pengajuan_tempo.city_id_pengiriman.id if pengajuan_tempo.city_id_pengiriman else '', + 'district_pengiriman': pengajuan_tempo.district_id_pengiriman.id if pengajuan_tempo.district_id_pengiriman else '', + 'subDistrict_pengiriman': pengajuan_tempo.subDistrict_id_pengiriman.id if pengajuan_tempo.subDistrict_id_pengiriman else '', + 'zip_pengiriman' : pengajuan_tempo.zip_pengiriman if pengajuan_tempo.zip_pengiriman else '', + 'invoice_pic_tittle' : pengajuan_tempo.invoice_pic_tittle if pengajuan_tempo.invoice_pic_tittle else '', + 'invoice_pic' : pengajuan_tempo.invoice_pic if pengajuan_tempo.invoice_pic else '', + 'street_invoice' : pengajuan_tempo.street_invoice if pengajuan_tempo.street_invoice else '', + 'state_invoice' : pengajuan_tempo.state_id_invoice.id if pengajuan_tempo.state_id_invoice else '', + 'city_invoice' : pengajuan_tempo.city_id_invoice.id if pengajuan_tempo.city_id_invoice else '', + 'district_invoice': pengajuan_tempo.district_id_invoice.id if pengajuan_tempo.district_id_invoice else '', + 'subDistrict_invoice': pengajuan_tempo.subDistrict_id_invoice.id if pengajuan_tempo.subDistrict_id_invoice else '', + 'zip_invoice': pengajuan_tempo.zip_invoice if pengajuan_tempo.zip_invoice else '', + 'tukar_invoice_input' : pengajuan_tempo.tukar_invoice if pengajuan_tempo.tukar_invoice else '', + 'tukar_invoice_input_pembayaran' : pengajuan_tempo.jadwal_bayar if pengajuan_tempo.jadwal_bayar else '', + 'dokumen_pengiriman' : ','.join(dokumen_pengiriman) if dokumen_pengiriman else '', + 'dokumen_pengiriman_input' : pengajuan_tempo.dokumen_pengiriman_input if pengajuan_tempo.dokumen_pengiriman_input else '', + 'dokumen_kirim_input' : pengajuan_tempo.dokumen_kirim_input if pengajuan_tempo.dokumen_kirim_input else '', + 'dokumen_pengiriman_invoice' : pengajuan_tempo.dokumen_invoice if pengajuan_tempo.dokumen_invoice else '', + 'is_same_addrees': pengajuan_tempo.is_same_address if pengajuan_tempo.is_same_address else False, + 'is_same_addrees_street': pengajuan_tempo.is_same_address_street if pengajuan_tempo.is_same_address_street else False, + 'supplier_ids': [ + { + 'id': supplier.id, + 'supplier': supplier.name_supplier, + 'telepon': supplier.phone, + 'pic': supplier.pic_name, + 'credit_limit': supplier.credit_limit, + 'durasi_tempo': supplier.tempo_duration + } + for supplier in pengajuan_tempo.supplier_ids + ] if pengajuan_tempo.supplier_ids else '', + # Dokumen + 'dokumen_npwp': + { + 'name': pengajuan_tempo.dokumen_npwp.name, + 'base64': pengajuan_tempo.dokumen_npwp.datas.decode('utf-8'), + 'format': pengajuan_tempo.dokumen_npwp.mimetype, + } if pengajuan_tempo.dokumen_npwp else '', + 'dokumen_sppkp': { + 'name': pengajuan_tempo.dokumen_sppkp.name, + 'base64': pengajuan_tempo.dokumen_sppkp.datas.decode('utf-8'), + 'format': pengajuan_tempo.dokumen_sppkp.mimetype, + } if pengajuan_tempo.dokumen_sppkp else '', + 'dokumen_nib': + { + 'name': pengajuan_tempo.dokumen_nib.name, + 'base64': pengajuan_tempo.dokumen_nib.datas.decode('utf-8'), + 'format': pengajuan_tempo.dokumen_nib.mimetype, + }if pengajuan_tempo.dokumen_nib else '', + 'dokumen_siup': + { + 'name': pengajuan_tempo.dokumen_siup.name, + 'base64': pengajuan_tempo.dokumen_siup.datas.decode('utf-8'), + 'format': pengajuan_tempo.dokumen_siup.mimetype, + }if pengajuan_tempo.dokumen_siup else '', + 'dokumen_tdp': + { + 'name': pengajuan_tempo.dokumen_tdp.name, + 'base64': pengajuan_tempo.dokumen_tdp.datas.decode('utf-8'), + 'format': pengajuan_tempo.dokumen_tdp.mimetype, + }if pengajuan_tempo.dokumen_tdp else '', + 'dokumen_skdp': + { + 'name': pengajuan_tempo.dokumen_skdp.name, + 'base64': pengajuan_tempo.dokumen_skdp.datas.decode('utf-8'), + 'format': pengajuan_tempo.dokumen_skdp.mimetype, + }if pengajuan_tempo.dokumen_skdp else '', + 'dokumen_skt': + { + 'name': pengajuan_tempo.dokumen_skt.name, + 'base64': pengajuan_tempo.dokumen_skt.datas.decode('utf-8'), + 'format': pengajuan_tempo.dokumen_skt.mimetype, + }if pengajuan_tempo.dokumen_skt else '', + 'dokumen_akta_perubahan': { + 'name': pengajuan_tempo.dokumen_akta_perubahan.name, + 'base64': pengajuan_tempo.dokumen_akta_perubahan.datas.decode('utf-8'), + 'format': pengajuan_tempo.dokumen_akta_perubahan.mimetype, + } if pengajuan_tempo.dokumen_akta_perubahan else '', + 'dokumen_ktp_dirut': { + 'name': pengajuan_tempo.dokumen_ktp_dirut.name, + 'base64': pengajuan_tempo.dokumen_ktp_dirut.datas.decode('utf-8'), + 'format': pengajuan_tempo.dokumen_ktp_dirut.mimetype, + } if pengajuan_tempo.dokumen_ktp_dirut else '', + 'dokumen_akta_pendirian': { + 'name': pengajuan_tempo.dokumen_akta_pendirian.name, + 'base64': pengajuan_tempo.dokumen_akta_pendirian.datas.decode('utf-8'), + 'format': pengajuan_tempo.dokumen_akta_pendirian.mimetype, + } if pengajuan_tempo.dokumen_akta_pendirian else '', + 'dokumen_laporan_keuangan': { + 'name': pengajuan_tempo.dokumen_laporan_keuangan.name, + 'base64': pengajuan_tempo.dokumen_laporan_keuangan.datas.decode('utf-8'), + 'format': pengajuan_tempo.dokumen_laporan_keuangan.mimetype, + } if pengajuan_tempo.dokumen_laporan_keuangan else '', + 'dokumen_foto_kantor': { + 'name': pengajuan_tempo.dokumen_foto_kantor.name, + 'base64': pengajuan_tempo.dokumen_foto_kantor.datas.decode('utf-8'), + 'format': pengajuan_tempo.dokumen_foto_kantor.mimetype, + } if pengajuan_tempo.dokumen_foto_kantor else '', + 'dokumen_tempat_bekerja': { + 'name': pengajuan_tempo.dokumen_tempat_bekerja.name, + 'base64': pengajuan_tempo.dokumen_tempat_bekerja.datas.decode('utf-8'), + 'format': pengajuan_tempo.dokumen_tempat_bekerja.mimetype, + } if pengajuan_tempo.dokumen_tempat_bekerja else '', + } + + return data
\ No newline at end of file diff --git a/indoteknik_api/models/res_users.py b/indoteknik_api/models/res_users.py index 1691acde..713bf50c 100644 --- a/indoteknik_api/models/res_users.py +++ b/indoteknik_api/models/res_users.py @@ -1,5 +1,5 @@ from odoo import models - +from odoo.http import request class ResUsers(models.Model): _inherit = 'res.users' @@ -14,6 +14,15 @@ class ResUsers(models.Model): 'manager': 2, 'director': 3 } + partner_tempo = False + is_tempo_request = request.env['user.pengajuan.tempo.request'].search([('user_company_id', '=', main_partner.id)], limit=1) + tempo_progres = ( + 'review' if is_tempo_request.state_tempo in ('draft', 'approval_sales', 'approval_finance') else + 'rejected' if is_tempo_request.state_tempo == 'reject' else + 'approve' if is_tempo_request.state_tempo == 'approval_director' else '' + ) + if main_partner: + partner_tempo = True if 'tempo' in main_partner.get_check_payment_term().lower() else False data = { 'id': res_user.id, @@ -32,7 +41,9 @@ class ResUsers(models.Model): 'feature': { 'so_approval': main_partner.use_so_approval, 'only_ready_stock': main_partner.use_only_ready_stock - } + }, + 'partner_tempo': partner_tempo, + 'tempo_progres': tempo_progres } return data @@ -70,7 +81,7 @@ class ResUsers(models.Model): data['state_id'] = { 'id': user.state_id.id, 'name': user.state_id.name - } or None + } or 0 if user.kota_id: data['city'] = { diff --git a/indoteknik_api/models/sale_order.py b/indoteknik_api/models/sale_order.py index 54e1fd40..727379c5 100644 --- a/indoteknik_api/models/sale_order.py +++ b/indoteknik_api/models/sale_order.py @@ -39,6 +39,8 @@ class SaleOrder(models.Model): data['status'] = 'cancel' if sale_order.state in ['draft', 'sent']: data['status'] = 'draft' + if sale_order.is_continue_transaction: + data['status'] = 'waiting' if sale_order.approval_status in ['pengajuan1', 'pengajuan2']: data['status'] = 'waiting' if sale_order.state == 'sale': @@ -85,6 +87,11 @@ class SaleOrder(models.Model): } product['quantity'] = line.product_uom_qty product['available_quantity'] = line.product_available_quantity + for data_v2 in sale_order.fulfillment_line_v2: + product_v2 = self.env['product.product'].api_single_response(data_v2.product_id) + if product['id'] == product_v2['id']: + product['so_qty'] = data_v2.so_qty + product['reserved_stock_qty'] = data_v2.reserved_stock_qty data_with_detail['products'].append(product) for invoice in sale_order.invoice_ids: if invoice.state == 'posted': |
