diff options
| author | Rafi Zadanly <zadanlyr@gmail.com> | 2023-02-13 10:41:41 +0700 |
|---|---|---|
| committer | Rafi Zadanly <zadanlyr@gmail.com> | 2023-02-13 10:41:41 +0700 |
| commit | cfa0aa5c242b14332f7bc970bb65f1fbde0a9f3b (patch) | |
| tree | 91f855964cadb0c76094cd2cc6b51f7994ce0c6d | |
| parent | fb04f8f3c533740c79c130ab4bc097b8529cae8e (diff) | |
| parent | 7478616937cff56ccb994138831f90eae904e724 (diff) | |
fix conflict
| -rw-r--r-- | indoteknik_api/controllers/api_v1/download.py | 46 | ||||
| -rw-r--r-- | indoteknik_api/controllers/api_v1/sale_order.py | 98 | ||||
| -rw-r--r-- | indoteknik_api/controllers/controller.py | 2 | ||||
| -rw-r--r-- | indoteknik_api/models/account_move.py | 4 | ||||
| -rw-r--r-- | indoteknik_api/models/rest_api.py | 32 | ||||
| -rw-r--r-- | indoteknik_api/models/sale_order.py | 2 | ||||
| -rw-r--r-- | indoteknik_custom/models/account_move.py | 13 | ||||
| -rwxr-xr-x | indoteknik_custom/models/user_activity_log.py | 68 | ||||
| -rw-r--r-- | indoteknik_custom/views/dunning_run.xml | 13 | ||||
| -rwxr-xr-x | indoteknik_custom/views/user_activity_log.xml | 21 |
10 files changed, 278 insertions, 21 deletions
diff --git a/indoteknik_api/controllers/api_v1/download.py b/indoteknik_api/controllers/api_v1/download.py index 36f775b5..d9353896 100644 --- a/indoteknik_api/controllers/api_v1/download.py +++ b/indoteknik_api/controllers/api_v1/download.py @@ -1,7 +1,6 @@ from .. import controller from odoo import http from odoo.http import request -import base64 class Download(controller.Controller): @@ -13,22 +12,41 @@ class Download(controller.Controller): ('res_field', '=', field), ('res_id', '=', id), ], ['datas', 'mimetype']) - return result if len(result) > 0 else None + return result[0] if len(result) > 0 else None - @http.route(PREFIX + 'download/invoice/<id>', auth='none', method=['GET']) - def download_invoice(self, **kw): - id = int(kw.get('id', 0)) - return request.render('account.report_invoice', {'id': id}) + @http.route(PREFIX + 'download/invoice/<id>/<token>', auth='none', method=['GET']) + def download_invoice(self, id, token): + id = int(id) + + rest_api = request.env['rest.api'] + md5_valid = rest_api.md5_salt_valid(id, 'account.move', token) + if not md5_valid: + return self.response('Unauthorized') + + account_move = request.env['account.move'].sudo().search_read([('id', '=', id)], ['name']) + pdf, type = request.env['ir.actions.report'].sudo().search([('report_name', '=', 'account.report_invoice')])._render_qweb_pdf([id]) + return rest_api.response_attachment({ + 'content': pdf, + 'mimetype': 'application/pdf', + 'filename': account_move[0]['name'] + }) @http.route(PREFIX + 'download/tax-invoice/<id>/<token>', auth='none', method=['GET']) def download_tax_invoice(self, id, token): id = int(id) - md5_by_id = request.env['rest.api'].md5_salt(id, 'account.move') - if md5_by_id == token: - attachment = self._get_attachment('account.move', 'efaktur_document', id) - if attachment: - return request.make_response(base64.b64decode(attachment['datas']), [('Content-Type', attachment['mimetype'])]) - return self.response('Dokumen tidak ditemukan', code=404) - - return self.response('Tidak diizinkan') + rest_api = request.env['rest.api'] + md5_valid = rest_api.md5_salt_valid(id, 'account.move', token) + if not md5_valid: + return self.response('Unauthorized') + + account_move = request.env['account.move'].sudo().search_read([('id', '=', id)], ['name']) + attachment = self._get_attachment('account.move', 'efaktur_document', id) + if attachment and len(account_move) > 0: + return rest_api.response_attachment({ + 'content': attachment['datas'], + 'decode_content': True, + 'mimetype': attachment['mimetype'], + 'filename': account_move[0]['name'], + }) + return self.response('Dokumen tidak ditemukan', code=404) diff --git a/indoteknik_api/controllers/api_v1/sale_order.py b/indoteknik_api/controllers/api_v1/sale_order.py index 57a933f9..5f888e6c 100644 --- a/indoteknik_api/controllers/api_v1/sale_order.py +++ b/indoteknik_api/controllers/api_v1/sale_order.py @@ -3,6 +3,7 @@ from odoo import http from odoo.http import request import json + class SaleOrder(controller.Controller): prefix = '/api/v1/' PREFIX_PARTNER = prefix + 'partner/<partner_id>/' @@ -119,7 +120,7 @@ class SaleOrder(controller.Controller): return self.unauthorized_response() if not params['valid']: return self.response(code=400, description=params) - + partner_child_ids = self.get_partner_child_ids(params['value']['partner_id']) domain = [ ('id', '=', params['value']['id']), @@ -133,6 +134,101 @@ class SaleOrder(controller.Controller): return self.response(data) + @http.route(PREFIX_PARTNER + 'sale_order/<id>/upload_po', auth='public', method=['POST', 'OPTIONS'], csrf=False) + def partner_upload_po_sale_order(self, **kw): + user_token = self.authenticate() + if not user_token: + return self.unauthorized_response() + + params = self.get_request_params(kw, { + 'partner_id': ['number'], + 'id': ['number'], + 'name': [], + 'file': [] + }) + if not user_token['partner_id'] == params['value']['partner_id']: + return self.unauthorized_response() + if not params['valid']: + return self.response(code=400, description=params) + partner_child_ids = self.get_partner_child_ids(params['value']['partner_id']) + domain = [ + ('id', '=', params['value']['id']), + ('partner_id', 'in', partner_child_ids) + ] + data = False + sale_order = request.env['sale.order'].search(domain) + if sale_order: + sale_order.partner_purchase_order_name = params['value']['name'] + sale_order.partner_purchase_order_file = params['value']['file'] + data = sale_order.id + return self.response(data) + + @http.route(PREFIX_PARTNER + 'sale_order/<id>/download_po/<token>', auth='none', method=['GET']) + def partner_download_po_sale_order(self, id, token): + id = int(id) + + rest_api = request.env['rest.api'] + md5_valid = rest_api.md5_salt_valid(id, 'sale.order', token) + if not md5_valid: + return self.response('Unauthorized') + + sale_order = request.env['sale.order'].sudo().search_read([('id', '=', id)], ['partner_purchase_order_name']) + attachment = rest_api.get_single_attachment('sale.order', 'partner_purchase_order_file', id) + if attachment and len(sale_order) > 0: + return rest_api.response_attachment({ + 'content': attachment['datas'], + 'decode_content': True, + 'mimetype': attachment['mimetype'], + 'filename': sale_order[0]['partner_purchase_order_name'] + }) + return self.response('Dokumen tidak ditemukan', code=404) + + @http.route(PREFIX_PARTNER + 'sale_order/<id>/download/<token>', auth='none', method=['GET']) + def partner_download_sale_order(self, id, token): + id = int(id) + + rest_api = request.env['rest.api'] + md5_valid = rest_api.md5_salt_valid(id, 'sale.order', token) + if not md5_valid: + return self.response('Unauthorized') + + sale_order = request.env['sale.order'].sudo().search_read([('id', '=', id)], ['name']) + pdf, type = request.env['ir.actions.report'].sudo().search([('report_name', '=', 'sale.report_saleorder')])._render_qweb_pdf([id]) + if pdf and len(sale_order) > 0: + return rest_api.response_attachment({ + 'content': pdf, + 'mimetype': 'application/pdf', + 'filename': sale_order[0]['name'] + }) + return self.response('Dokumen tidak ditemukan', code=404) + + @http.route(PREFIX_PARTNER + 'sale_order/<id>/cancel', auth='public', method=['POST', 'OPTIONS'], csrf=False) + def partner_cancel_sale_order(self, **kw): + user_token = self.authenticate() + if not user_token: + return self.unauthorized_response() + + params = self.get_request_params(kw, { + 'partner_id': ['number'], + 'id': ['number'] + }) + if not user_token['partner_id'] == params['value']['partner_id']: + return self.unauthorized_response() + if not params['valid']: + return self.response(code=400, description=params) + + partner_child_ids = self.get_partner_child_ids(params['value']['partner_id']) + domain = [ + ('id', '=', params['value']['id']), + ('partner_id', 'in', partner_child_ids) + ] + data = False + sale_order = request.env['sale.order'].search(domain) + if sale_order: + sale_order.state = 'cancel' + data = sale_order.id + return self.response(data) + @http.route(PREFIX_PARTNER + 'sale_order/checkout', auth='public', method=['POST', 'OPTIONS'], csrf=False) def create_partner_sale_order(self, **kw): user_token = self.authenticate() diff --git a/indoteknik_api/controllers/controller.py b/indoteknik_api/controllers/controller.py index c90d3ff1..59885148 100644 --- a/indoteknik_api/controllers/controller.py +++ b/indoteknik_api/controllers/controller.py @@ -86,6 +86,7 @@ class Controller(http.Controller): return time def response(self, data=[], code=200, description='OK'): + request.env['user.activity.log'].record_activity() response = { 'status': { 'code': code, @@ -149,4 +150,5 @@ class Controller(http.Controller): def get_image(self, model, field, id): model = request.env[model].sudo().search([('id', '=', id)], limit=1) image = model[field] if model[field] else '' + request.env['user.activity.log'].record_activity() return request.make_response(base64.b64decode(image), [('Content-Type', 'image/jpg')]) diff --git a/indoteknik_api/models/account_move.py b/indoteknik_api/models/account_move.py index f77ded16..5c31f010 100644 --- a/indoteknik_api/models/account_move.py +++ b/indoteknik_api/models/account_move.py @@ -1,6 +1,5 @@ import datetime from odoo import models -import hashlib class AccountMove(models.Model): @@ -8,6 +7,7 @@ class AccountMove(models.Model): def api_v1_single_response(self, account_move, context=False): data = { + 'token': self.env['rest.api'].md5_salt(account_move.id, 'account.move'), 'id': account_move.id, 'name': account_move.name, 'purchase_order_name': account_move.ref or '', @@ -16,7 +16,7 @@ class AccountMove(models.Model): 'amount_total': account_move.amount_total, 'amount_residual': account_move.amount_residual, 'invoice_date': '', - 'efaktur_token': self.env['rest.api'].md5_salt(account_move.id, 'account.move') if account_move.efaktur_document else '', + 'efaktur': True if account_move.efaktur_document else False, } if isinstance(object, datetime.date): data['invoice_date'] = account_move.invoice_date.strftime('%d/%m/%Y') diff --git a/indoteknik_api/models/rest_api.py b/indoteknik_api/models/rest_api.py index 052800b7..65119b52 100644 --- a/indoteknik_api/models/rest_api.py +++ b/indoteknik_api/models/rest_api.py @@ -1,7 +1,9 @@ from odoo import models +from odoo.http import request import datetime from pytz import timezone import hashlib +import base64 class RestApi(models.TransientModel): @@ -14,4 +16,32 @@ class RestApi(models.TransientModel): return time def md5_salt(self, value, salt): - return hashlib.md5((salt + '$' + str(value)).encode()).hexdigest()
\ No newline at end of file + return hashlib.md5((salt + '$' + str(value)).encode()).hexdigest() + + def md5_salt_valid(self, value, salt, token): + return hashlib.md5((salt + '$' + str(value)).encode()).hexdigest() == token + + def get_single_attachment(self, model, field, id): + domain = [ + ('res_model', '=', model), + ('res_field', '=', field), + ('res_id', '=', id), + ] + fields = ['datas', 'mimetype'] + result = self.env['ir.attachment'].sudo().search_read(domain, fields) + return result[0] if len(result) > 0 else None + + def response_attachment(self, data = {}): + decode_content = data.get('decode_content', False) + if decode_content: + data['content'] = base64.b64decode(data['content']) + + return request.make_response( + data['content'], + [ + ('Content-Type', data['mimetype']), + ('Content-Disposition', 'attachment; filename=%s' % data['filename']), + ('Content-Length', len(data['content'])) + ] + ) +
\ No newline at end of file diff --git a/indoteknik_api/models/sale_order.py b/indoteknik_api/models/sale_order.py index afaf6ae6..7ce8ff61 100644 --- a/indoteknik_api/models/sale_order.py +++ b/indoteknik_api/models/sale_order.py @@ -6,11 +6,13 @@ class SaleOrder(models.Model): def api_v1_single_response(self, sale_order, context=False): data = { + 'token': self.env['rest.api'].md5_salt(sale_order.id, 'sale.order'), 'id': sale_order.id, 'name': sale_order.name, 'sales': sale_order.user_id.name, 'amount_total': sale_order.amount_total, 'purchase_order_name': sale_order.partner_purchase_order_name, + 'purchase_order_file': True if sale_order.partner_purchase_order_file else False, 'invoice_count': sale_order.invoice_count, 'status': 'draft', } diff --git a/indoteknik_custom/models/account_move.py b/indoteknik_custom/models/account_move.py index 1e0c56cf..54e51dcf 100644 --- a/indoteknik_custom/models/account_move.py +++ b/indoteknik_custom/models/account_move.py @@ -1,4 +1,5 @@ from odoo import models, api, fields +from odoo.exceptions import AccessError, UserError, ValidationError from datetime import timedelta @@ -12,6 +13,18 @@ class AccountMove(models.Model): date_terima_tukar_faktur = fields.Date(string='Terima Faktur') shipper_faktur_id = fields.Many2one('delivery.carrier', string='Shipper Faktur') + def button_draft(self): + res = super(AccountMove, self).button_draft() + if not self.env.user.is_accounting: + raise UserError('Hanya Accounting yang bisa Reset to Draft') + return res + + def action_post(self): + res = super(AccountMove, self).action_post() + if not self.env.user.is_accounting: + raise UserError('Hanya Accounting yang bisa Posting') + return res + @api.onchange('date_kirim_tukar_faktur') def change_date_kirim_tukar_faktur(self): for invoice in self: diff --git a/indoteknik_custom/models/user_activity_log.py b/indoteknik_custom/models/user_activity_log.py index 32b389a1..9d9694af 100755 --- a/indoteknik_custom/models/user_activity_log.py +++ b/indoteknik_custom/models/user_activity_log.py @@ -1,6 +1,9 @@ -from odoo import models, fields +from odoo import models, fields, api +from odoo.http import request from datetime import datetime, timedelta import logging, re +import requests +import json _logger = logging.getLogger(__name__) @@ -11,11 +14,74 @@ class UserActivityLog(models.Model): page_title = fields.Char(string="Judul Halaman") url = fields.Char(string="URL") + ip_address = fields.Char('IP Address') + ip_address_lookup = fields.Text('IP Address Lookup') + ip_location_city = fields.Text('IP Location City') + ip_location_country = fields.Text('IP Location Country') + ip_location_country_code = fields.Text('IP Location Country Code') + ip_location_map = fields.Html('Embedded Map', compute='_compute_ip_location_map', sanitize=False) res_user_id = fields.Many2one("res.users", string="User") email = fields.Char(string="Email") update_product = fields.Boolean(string="Update Product") product_id = fields.Many2one('product.template', string='Product') + def _parse_json(self, json_string, key): + result = '' + if json_string: + json_object = json.loads(json_string) + if key in json_object: + result = json_object[key] + return result + + def _compute_ip_location_map(self): + self.ip_location_map = "" + ip_location_lat = self._parse_json(self.ip_address_lookup, 'lat') + ip_location_lon = self._parse_json(self.ip_address_lookup, 'lon') + url = 'https://maps.google.com/maps?q=%s,%s&hl=id&z=15&output=embed' % (ip_location_lat, ip_location_lon) + if ip_location_lat and ip_location_lon: + self.ip_location_map = "<iframe width='100%' height='500' frameborder='1' scrolling='no' src='"+ url +"'></iframe>" + + def _parse_ip_location(self): + domain = [ + ('ip_address_lookup', '!=', False), + ('ip_location_city', '=', False), + ('ip_location_country', '=', False), + ('ip_location_country_code', '=', False), + ] + logs = self.search(domain, limit=200, order='create_date asc') + for log in logs: + log.ip_location_city = self._parse_json(log.ip_address_lookup, 'city') + log.ip_location_country = self._parse_json(log.ip_address_lookup, 'country') + log.ip_location_country_code = self._parse_json(log.ip_address_lookup, 'countryCode') + + def _load_ip_address_lookup(self): + domain = [ + ('ip_address', '!=', False), + ('ip_address_lookup', '=', False), + ] + logs = self.search(domain, limit=100, order='create_date asc') + for log in logs: + try: + ipinfo = requests.get('http://ip-api.com/json/%s' % log.ip_address).json() + del ipinfo['status'] + log.ip_address_lookup = json.dumps(ipinfo, indent=4, sort_keys=True) + except: + log.ip_address_lookup = '' + self._parse_ip_location() + + def record_activity(self): + try: + httprequest = request.httprequest + if httprequest.remote_addr != '127.0.0.1': + self.env['user.activity.log'].sudo().create([{ + 'page_title': request.env['ir.config_parameter'].get_param('web.base.url'), + 'url': httprequest.base_url, + 'ip_address': httprequest.remote_addr + }]) + return True + except: + return False + def compile_product(self): logs = self.env['user.activity.log'].search([ ('email', '!=', False), diff --git a/indoteknik_custom/views/dunning_run.xml b/indoteknik_custom/views/dunning_run.xml index c251b206..6343a79b 100644 --- a/indoteknik_custom/views/dunning_run.xml +++ b/indoteknik_custom/views/dunning_run.xml @@ -82,10 +82,23 @@ </field> </record> + <record id="view_dunning_run_filter" model="ir.ui.view"> + <field name="name">dunning.run.list.select</field> + <field name="model">dunning.run</field> + <field name="priority" eval="15"/> + <field name="arch" type="xml"> + <search string="Search Dunning Run"> + <field name="number"/> + <field name="partner_id"/> + </search> + </field> + </record> + <record id="dunning_run_action" model="ir.actions.act_window"> <field name="name">Dunning Run</field> <field name="type">ir.actions.act_window</field> <field name="res_model">dunning.run</field> + <field name="search_view_id" ref="view_dunning_run_filter"/> <field name="view_mode">tree,form</field> </record> diff --git a/indoteknik_custom/views/user_activity_log.xml b/indoteknik_custom/views/user_activity_log.xml index db242505..b8792ee8 100755 --- a/indoteknik_custom/views/user_activity_log.xml +++ b/indoteknik_custom/views/user_activity_log.xml @@ -4,9 +4,10 @@ <field name="name">user.activity.log.tree</field> <field name="model">user.activity.log</field> <field name="arch" type="xml"> - <tree default_order="create_date desc"> + <tree default_order="create_date desc" create="0" export_xlsx="0"> <field name="create_date"/> <field name="page_title"/> + <field name="ip_address"/> <field name="url" widget="url"/> <field name="res_user_id"/> <field name="email"/> @@ -18,7 +19,7 @@ <field name="name">user.activity.log.form</field> <field name="model">user.activity.log</field> <field name="arch" type="xml"> - <form> + <form create="0" edit="0"> <sheet> <group> <group> @@ -27,8 +28,24 @@ <field name="url" widget="url"/> <field name="res_user_id"/> <field name="email"/> + <field name="ip_address"/> </group> </group> + <notebook> + <page string="IP Lookup Detail"> + <group> + <field name="ip_location_city"/> + <field name="ip_location_country"/> + <field name="ip_location_country_code"/> + </group> + </page> + <page string="IP Address Lookup"> + <field name="ip_address_lookup"/> + </page> + <page string="IP Address Location"> + <field name="ip_location_map" widget="html" /> + </page> + </notebook> </sheet> </form> </field> |
