summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorstephanchrst <stephanchrst@gmail.com>2023-02-10 10:36:16 +0700
committerstephanchrst <stephanchrst@gmail.com>2023-02-10 10:36:16 +0700
commitbbf176b0ce51ade22b74d0df2023025a4cef3efa (patch)
tree24d2d3c7e3fed5c0672a9063a09e3c4d33ba3dac
parentbd01d7a842c8b6e4aea6a2fc3615a9d57fbcd470 (diff)
parentb0de64ae769148a009d0a08a957c5c35dee174a9 (diff)
Merge branch 'release' into line_no_sales_order
-rw-r--r--indoteknik_api/controllers/api_v1/__init__.py2
-rw-r--r--indoteknik_api/controllers/api_v1/category.py63
-rw-r--r--indoteknik_api/controllers/api_v1/download.py52
-rw-r--r--indoteknik_api/controllers/api_v1/invoice.py25
-rw-r--r--indoteknik_api/controllers/api_v1/midtrans.py42
-rw-r--r--indoteknik_api/controllers/api_v1/sale_order.py156
-rw-r--r--indoteknik_api/controllers/api_v1/wishlist.py66
-rw-r--r--indoteknik_api/controllers/controller.py13
-rw-r--r--indoteknik_api/models/__init__.py1
-rw-r--r--indoteknik_api/models/account_move.py30
-rw-r--r--indoteknik_api/models/rest_api.py47
-rw-r--r--indoteknik_api/models/sale_order.py45
-rwxr-xr-xindoteknik_custom/models/__init__.py1
-rw-r--r--indoteknik_custom/models/account_move.py4
-rw-r--r--indoteknik_custom/models/dunning_run.py3
-rw-r--r--indoteknik_custom/models/midtrans.py38
-rwxr-xr-xindoteknik_custom/models/user_activity_log.py68
-rwxr-xr-xindoteknik_custom/security/ir.model.access.csv5
-rw-r--r--indoteknik_custom/views/dunning_run.xml1
-rwxr-xr-xindoteknik_custom/views/user_activity_log.xml22
20 files changed, 620 insertions, 64 deletions
diff --git a/indoteknik_api/controllers/api_v1/__init__.py b/indoteknik_api/controllers/api_v1/__init__.py
index a4776503..63540928 100644
--- a/indoteknik_api/controllers/api_v1/__init__.py
+++ b/indoteknik_api/controllers/api_v1/__init__.py
@@ -4,6 +4,7 @@ from . import cart
from . import category
from . import city
from . import district
+from . import download
from . import flash_sale
from . import invoice
from . import manufacture
@@ -18,3 +19,4 @@ from . import wishlist
from . import brand_homepage
from . import customer
from . import content
+from . import midtrans
diff --git a/indoteknik_api/controllers/api_v1/category.py b/indoteknik_api/controllers/api_v1/category.py
index 62faff85..ff1baf6b 100644
--- a/indoteknik_api/controllers/api_v1/category.py
+++ b/indoteknik_api/controllers/api_v1/category.py
@@ -7,12 +7,73 @@ import ast
class Category(controller.Controller):
prefix = '/api/v1/'
+ @http.route(prefix + 'category/child', auth='public', methods=['GET', 'OPTIONS'])
+ def get_category_child(self, **kw):
+ user_token = self.authenticate()
+ if not user_token:
+ return self.unauthorized_response()
+
+ params = self.get_request_params(kw, {
+ 'parent_id': ['number', 'default:0']
+ })
+ if not params['valid']:
+ return self.response(code=400, description=params)
+ if params['value']['parent_id'] == 0:
+ params['value']['parent_id'] = False
+
+ categories = request.env['product.public.category'].search_read([('parent_frontend_id', '=', params['value']['parent_id'])], ['id', 'name'])
+ return self.response(categories)
+
+ @http.route(prefix + 'category/tree', auth='public', methods=['GET', 'OPTIONS'])
+ def get_category_tree(self, **kw):
+ user_token = self.authenticate()
+ if not user_token:
+ return self.unauthorized_response()
+
+ parent_categories = request.env['product.public.category'].search_read([('parent_frontend_id', '=', False)], ['id', 'name'])
+ data = []
+ for parent_category in parent_categories:
+ parent_data = {
+ 'id': parent_category['id'],
+ 'name': parent_category['name'],
+ 'childs': []
+ }
+ child_1_categories = request.env['product.public.category'].search_read([('parent_frontend_id', '=', parent_category['id'])], ['id', 'name'])
+ for child_1_category in child_1_categories:
+ child_1_data = {
+ 'id': child_1_category['id'],
+ 'name': child_1_category['name'],
+ 'childs': []
+ }
+ child_2_categories = request.env['product.public.category'].search_read([('parent_frontend_id', '=', child_1_category['id'])], ['id', 'name'])
+ for child_2_category in child_2_categories:
+ child_2_data = {
+ 'id': child_2_category['id'],
+ 'name': child_2_category['name'],
+ }
+ child_1_data['childs'].append(child_2_data)
+ parent_data['childs'].append(child_1_data)
+ data.append(parent_data)
+ return self.response(data)
+
+ @http.route(prefix + 'categories_homepage/ids', auth='public', methods=['GET', 'OPTIONS'])
+ def get_categories_homepage_count(self, **kw):
+ if not self.authenticate():
+ return self.response(code=401, description='Unauthorized')
+ query = [('status', '=', 'tayang')]
+ categories = request.env['website.categories.homepage'].search_read(query, ['id'])
+ return self.response([x['id'] for x in categories])
+
+
@http.route(prefix + 'categories_homepage', auth='public', methods=['GET', 'OPTIONS'])
def get_categories_homepage(self, **kw):
if not self.authenticate():
return self.response(code=401, description='Unauthorized')
base_url = request.env['ir.config_parameter'].get_param('web.base.url')
query = [('status', '=', 'tayang')]
+ id = kw.get('id')
+ if id:
+ query.append(('id', '=', id))
categories = request.env['website.categories.homepage'].search(query, order='sequence')
data = []
for category in categories:
@@ -33,7 +94,7 @@ class Category(controller.Controller):
'sequence': category.sequence,
'category_id': category.category_id.id,
'name': category.category_id.name,
- 'image': base_url + 'api/image/website.categories.homepage/image/' + str(category.id) if category.image else '',
+ 'image': request.env['ir.attachment'].api_image('website.categories.homepage', 'image', category.id),
'url': category.url,
# 'brands': [y.x_name for y in brands],
'brands': [request.env['x_manufactures'].api_single_response(y) for y in brands],
diff --git a/indoteknik_api/controllers/api_v1/download.py b/indoteknik_api/controllers/api_v1/download.py
new file mode 100644
index 00000000..d9353896
--- /dev/null
+++ b/indoteknik_api/controllers/api_v1/download.py
@@ -0,0 +1,52 @@
+from .. import controller
+from odoo import http
+from odoo.http import request
+
+
+class Download(controller.Controller):
+ PREFIX = '/api/v1/'
+
+ def _get_attachment(self, model, field, id):
+ result = request.env['ir.attachment'].sudo().search_read([
+ ('res_model', '=', model),
+ ('res_field', '=', field),
+ ('res_id', '=', id),
+ ], ['datas', 'mimetype'])
+ return result[0] if len(result) > 0 else None
+
+ @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)
+
+ 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/invoice.py b/indoteknik_api/controllers/api_v1/invoice.py
index 5a6e8316..59cacfc4 100644
--- a/indoteknik_api/controllers/api_v1/invoice.py
+++ b/indoteknik_api/controllers/api_v1/invoice.py
@@ -34,7 +34,11 @@ class Invoice(controller.Controller):
]
if params['value']['name']:
name = params['value']['name'].replace(' ', '%')
- domain.append(('name', 'ilike', '%'+ name +'%'))
+ domain += [
+ '|',
+ ('name', 'ilike', '%'+ name +'%'),
+ ('ref', 'ilike', '%'+ name +'%')
+ ]
invoices = request.env['account.move'].search(domain, offset=offset, limit=limit)
data = {
'invoice_total': request.env['account.move'].search_count(domain),
@@ -67,23 +71,6 @@ class Invoice(controller.Controller):
data = {}
account_move = request.env['account.move'].search(domain)
if account_move:
- res_users = request.env['res.users']
- data = {
- 'id': account_move.id,
- 'name': account_move.name,
- 'purchase_order_name': account_move.ref or '',
- 'payment_term': account_move.invoice_payment_term_id.name or '',
- 'sales': account_move.invoice_user_id.name,
- 'amount_total': account_move.amount_total,
- 'amount_residual': account_move.amount_residual,
- 'invoice_date': account_move.invoice_date.strftime('%d/%m/%Y') or '',
- 'invoice_date_due': account_move.invoice_date_due.strftime('%d/%m/%Y') or '',
- 'customer': res_users.api_address_response(account_move.partner_id),
- 'products': [],
- }
- for line in account_move.invoice_line_ids:
- product = request.env['product.product'].api_single_response(line.product_id)
- product['quantity'] = line.quantity
- data['products'].append(product)
+ data = request.env['account.move'].api_v1_single_response(account_move, context='with_detail')
return self.response(data)
diff --git a/indoteknik_api/controllers/api_v1/midtrans.py b/indoteknik_api/controllers/api_v1/midtrans.py
new file mode 100644
index 00000000..fdc801d3
--- /dev/null
+++ b/indoteknik_api/controllers/api_v1/midtrans.py
@@ -0,0 +1,42 @@
+from .. import controller
+from odoo import http
+from odoo.http import request
+import json
+
+
+class Midtrans(controller.Controller):
+ prefix = '/api/v1/'
+
+ @http.route(prefix + 'midtrans/notification', auth='none', type='json', csrf=False, cors='*', methods=['POST', 'OPTIONS'])
+ def notification(self, **kw):
+ json_raw = json.loads(request.httprequest.data)
+ trx_status = json.loads(request.httprequest.data)['transaction_status']
+ order_no = json.loads(request.httprequest.data)['order_id']
+
+ query = [('name', '=', order_no)]
+ order = request.env['sale.order'].sudo().search(query, limit=1)
+ order.payment_status = trx_status
+
+ request.env['midtrans.notification'].create([{
+ 'sale_order_id': order.id,
+ 'json_raw': json_raw,
+ 'payment_status': trx_status,
+ }])
+
+ return
+
+ @http.route(prefix + 'midtrans/recurring', auth='none', type='json', csrf=False, cors='*', methods=['POST', 'OPTIONS'])
+ def recurring(self, **kw):
+ json_raw = json.loads(request.httprequest.data)
+ request.env['midtrans.recurring'].create([{
+ 'json_raw': json_raw,
+ }])
+ return
+
+ @http.route(prefix + 'midtrans/payaccount', auth='none', type='json', csrf=False, cors='*', methods=['POST', 'OPTIONS'])
+ def payaccount(self, **kw):
+ json_raw = json.loads(request.httprequest.data)
+ request.env['midtrans.account'].create([{
+ 'json_raw': json_raw,
+ }])
+ return \ 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 f2ec8dfe..1c67d6c5 100644
--- a/indoteknik_api/controllers/api_v1/sale_order.py
+++ b/indoteknik_api/controllers/api_v1/sale_order.py
@@ -3,12 +3,14 @@ from odoo import http
from odoo.http import request
import json
+
class SaleOrder(controller.Controller):
prefix = '/api/v1/'
PREFIX_PARTNER = prefix + 'partner/<partner_id>/'
@http.route(prefix + "sale_order_number", auth='public', method=['GET', 'OPTIONS'])
def get_number_sale_order(self, **kw):
+ # for midtrans only
user_token = self.authenticate()
if not user_token:
return self.unauthorized_response()
@@ -16,11 +18,31 @@ class SaleOrder(controller.Controller):
sale_order_id = int(kw.get('sale_order_id', '0'))
sale_number = str(kw.get('sale_number', ''))
if sale_order_id > 0:
- sales = request.env['sale.order'].search_read([('id', '=', sale_order_id)], fields=['id', 'name', 'amount_total', 'state'])
+ query = [('id', '=', sale_order_id)]
+ # sales = request.env['sale.order'].search_read([('id', '=', sale_order_id)], fields=['id', 'name', 'amount_total', 'state'])
+ sales = request.env['sale.order'].search(query, limit=1)
else:
- sales = request.env['sale.order'].search_read([('name', '=', sale_number)], fields=['id', 'name', 'amount_total', 'state'])
+ query = [('name', '=', sale_number)]
+ # sales = request.env['sale.order'].search_read([('name', '=', sale_number)], fields=['id', 'name', 'amount_total', 'state'])
+ sales = request.env['sale.order'].search(query, limit=1)
+ data = []
+ for sale in sales:
+ product_name = ''
+ product_not_in_id = 0
+ for line in sale.order_line:
+ product_name = line.product_id.name
+ product_not_in_id = line.product_id.id
+ break
+ data.append({
+ 'id': sale.id,
+ 'name': sale.name,
+ 'amount_total': sale.amount_total,
+ 'state': sale.state,
+ 'product_name': product_name,
+ 'product_not_in_id': product_not_in_id,
+ })
- return self.response(sales)
+ return self.response(data)
@http.route(PREFIX_PARTNER + 'sale_order', auth='public', method=['GET', 'OPTIONS'])
def get_partner_sale_order(self, **kw):
@@ -45,7 +67,11 @@ class SaleOrder(controller.Controller):
domain = [('partner_id', 'in', partner_child_ids)]
if params['value']['name']:
name = params['value']['name'].replace(' ', '%')
- domain.append(('name', 'ilike', '%'+ name +'%'))
+ domain += [
+ '|',
+ ('name', 'ilike', '%'+ name +'%'),
+ ('partner_purchase_order_name', 'ilike', '%'+ name +'%')
+ ]
sale_orders = request.env['sale.order'].search(domain, offset=offset, limit=limit)
data = {
'sale_order_total': request.env['sale.order'].search_count(domain),
@@ -76,29 +102,105 @@ class SaleOrder(controller.Controller):
data = {}
sale_order = request.env['sale.order'].search(domain)
if sale_order:
- res_users = request.env['res.users']
- data = {
- 'id': sale_order.id,
- 'name': sale_order.name,
- 'payment_term': sale_order.payment_term_id.name or '',
- 'sales': sale_order.user_id.name or '',
- 'date_order': self.time_to_str(sale_order.date_order, '%d/%m/%Y %H:%M:%S'),
- 'purchase_order_name': sale_order.partner_purchase_order_name,
- 'products': [],
- 'amount_total': sale_order.amount_total,
- 'address': {
- '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)
- }
- }
- for line in sale_order.order_line:
- product = request.env['product.product'].api_single_response(line.product_id)
- product['quantity'] = line.product_uom_qty
- data['products'].append(product)
+ data = request.env['sale.order'].api_v1_single_response(sale_order, context='with_detail')
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()
@@ -115,6 +217,7 @@ class SaleOrder(controller.Controller):
'order_line': ['required', 'default:[]'],
'po_number': [],
'po_file': [],
+ 'type': [],
})
if not user_token['partner_id'] == params['value']['partner_id']:
@@ -139,10 +242,11 @@ class SaleOrder(controller.Controller):
'real_shipping_id': params['value']['partner_shipping_id'],
'partner_invoice_id': params['value']['partner_invoice_id'],
'partner_purchase_order_name': params['value']['po_number'],
- 'partner_purchase_order_file': params['value']['po_file']
+ 'partner_purchase_order_file': params['value']['po_file'],
}
+ if params['value']['type'] == 'sale_order':
+ parameters['approval_status'] = 'pengajuan1'
sale_order = request.env['sale.order'].create([[parameters]])
-
order_line = json.loads(params['value']['order_line'])
parameters = []
for line in order_line:
diff --git a/indoteknik_api/controllers/api_v1/wishlist.py b/indoteknik_api/controllers/api_v1/wishlist.py
index 9860f40b..a3299033 100644
--- a/indoteknik_api/controllers/api_v1/wishlist.py
+++ b/indoteknik_api/controllers/api_v1/wishlist.py
@@ -5,6 +5,7 @@ from odoo.http import request
class Wishlist(controller.Controller):
prefix = '/api/v1/'
+ PREFIX_USER = prefix + 'user/<user_id>/'
@http.route(prefix + 'wishlist', auth='public', methods=['GET'])
def get_wishlist_by_user_id(self, **kw):
@@ -71,3 +72,68 @@ class Wishlist(controller.Controller):
create = request.env['website.user.wishlist'].create(params)
result['id'] = create.id
return self.response(result)
+
+ @http.route(PREFIX_USER + 'wishlist', auth='public', methods=['GET', 'OPTIONS'])
+ def get_user_wishlist(self, **kw):
+ user_token = self.authenticate()
+ if not user_token:
+ return self.unauthorized_response()
+
+ params = self.get_request_params(kw, {
+ 'user_id': ['number'],
+ 'product_id': ['number'],
+ 'limit': ['default:0', 'number'],
+ 'offset': ['default:0', 'number'],
+ })
+ limit = params['value']['limit']
+ offset = params['value']['offset']
+ if not user_token['id'] == params['value']['user_id']:
+ return self.unauthorized_response()
+ if not params['valid']:
+ return self.response(code=400, description=params)
+
+ domain = [
+ ('user_id', '=', params['value']['user_id']),
+ ('variant_id', '=', False)
+ ]
+ if params['value']['product_id']:
+ domain.append(('product_id', '=', params['value']['product_id']))
+ wishlists = request.env['website.user.wishlist'].search(domain, limit=limit, offset=offset, order='create_date DESC')
+ product = []
+ for wishlist in wishlists:
+ product.append(request.env['product.template'].api_single_response(wishlist.product_id))
+ data = {
+ 'product_total': request.env['website.user.wishlist'].search_count(domain),
+ 'products': product
+ }
+ return self.response(data)
+
+ @http.route(PREFIX_USER + 'wishlist/create-or-delete', auth='public', methods=['POST', 'OPTIONS'], csrf=False)
+ def create_or_delete_user_wishlist(self, **kw):
+ user_token = self.authenticate()
+ if not user_token:
+ return self.unauthorized_response()
+
+ params = self.get_request_params(kw, {
+ 'user_id': ['number'],
+ 'product_id': ['required', 'number'],
+ })
+ if not user_token['id'] == params['value']['user_id']:
+ return self.unauthorized_response()
+ if not params['valid']:
+ return self.response(code=400, description=params)
+
+ query = [
+ ('user_id', '=', params['value']['user_id']),
+ ('product_id', '=', params['value']['product_id'])
+ ]
+ wishlist = request.env['website.user.wishlist'].search(query, limit=1)
+ result = {}
+ if wishlist:
+ wishlist.unlink()
+ result['id'] = wishlist.id
+ else:
+ create = request.env['website.user.wishlist'].create(params['value'])
+ result['id'] = create.id
+ return self.response(result)
+ \ No newline at end of file
diff --git a/indoteknik_api/controllers/controller.py b/indoteknik_api/controllers/controller.py
index a1a81e37..59885148 100644
--- a/indoteknik_api/controllers/controller.py
+++ b/indoteknik_api/controllers/controller.py
@@ -7,11 +7,8 @@ from odoo import http
from odoo.http import request
from odoo.tools.config import config
from pytz import timezone
-import logging
import jwt
-_logger = logging.getLogger(__name__)
-
class Controller(http.Controller):
jwt_secret_key = "NTNv7j0TuYARvmNMmWXo6fKvM4o6nvaUi9ryX38ZHL1bkrnD1ObOQ8JAUmHCBq7Iy7otZcyAagBLHVKvvYaIpmMuxmARQ97jUVG16Jkpkp1wXOPsrF9zwew6TpczyHkHgX5EuLg2MeBuiTqJACs1J0apruOOJCggOtkjB4c"
@@ -89,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,
@@ -138,10 +136,10 @@ class Controller(http.Controller):
return False
def get_partner_child_ids(self, partner_id):
- parent_partner_id = request.env['res.partner'].search([('id', '=', partner_id)], limit=1)
- parent_partner_id = parent_partner_id.parent_id.id or parent_partner_id.id
- partner_childs = request.env['res.partner'].search([('parent_id', '=', int(parent_partner_id))])
- partner_child_ids = [v['id'] for v in partner_childs] + [partner_id]
+ partner = request.env['res.partner'].search([('id', '=', partner_id)], limit=1)
+ 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('/api/token', auth='public', methods=['GET', 'OPTIONS'])
@@ -152,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/__init__.py b/indoteknik_api/models/__init__.py
index 9af9f36e..892d2657 100644
--- a/indoteknik_api/models/__init__.py
+++ b/indoteknik_api/models/__init__.py
@@ -4,6 +4,7 @@ from . import product_pricelist
from . import product_product
from . import product_template
from . import res_users
+from . import rest_api
from . import sale_order
from . import x_manufactures
from . import website_content
diff --git a/indoteknik_api/models/account_move.py b/indoteknik_api/models/account_move.py
index 9fd6fb18..5c31f010 100644
--- a/indoteknik_api/models/account_move.py
+++ b/indoteknik_api/models/account_move.py
@@ -1,13 +1,13 @@
import datetime
from odoo import models
-from pytz import timezone
class AccountMove(models.Model):
_inherit = 'account.move'
- def api_v1_single_response(self, account_move):
+ 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 '',
@@ -15,6 +15,30 @@ class AccountMove(models.Model):
'sales': account_move.invoice_user_id.name,
'amount_total': account_move.amount_total,
'amount_residual': account_move.amount_residual,
- 'invoice_date': account_move.invoice_date.strftime('%d/%m/%Y') or ''
+ 'invoice_date': '',
+ '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')
+ if context:
+ if context == 'with_detail':
+ res_users = self.env['res.users']
+ data_with_detail = {
+ 'id': account_move.id,
+ 'name': account_move.name,
+ 'purchase_order_name': account_move.ref or '',
+ 'payment_term': account_move.invoice_payment_term_id.name or '',
+ 'sales': account_move.invoice_user_id.name,
+ 'amount_total': account_move.amount_total,
+ 'amount_residual': account_move.amount_residual,
+ 'invoice_date': account_move.invoice_date.strftime('%d/%m/%Y') or '',
+ 'invoice_date_due': account_move.invoice_date_due.strftime('%d/%m/%Y') or '',
+ 'customer': res_users.api_address_response(account_move.partner_id),
+ 'products': [],
+ }
+ for line in account_move.invoice_line_ids:
+ product = self.env['product.product'].api_single_response(line.product_id)
+ product['quantity'] = line.quantity
+ data_with_detail['products'].append(product)
+ data.update(data_with_detail)
return data
diff --git a/indoteknik_api/models/rest_api.py b/indoteknik_api/models/rest_api.py
new file mode 100644
index 00000000..65119b52
--- /dev/null
+++ b/indoteknik_api/models/rest_api.py
@@ -0,0 +1,47 @@
+from odoo import models
+from odoo.http import request
+import datetime
+from pytz import timezone
+import hashlib
+import base64
+
+
+class RestApi(models.TransientModel):
+ _name = 'rest.api'
+
+ def datetime_to_str(self, object, format):
+ time = ''
+ if isinstance(object, datetime.datetime):
+ time = object.astimezone(timezone('Asia/Jakarta')).strftime(format)
+ return time
+
+ def md5_salt(self, value, salt):
+ 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 3359ee6a..c3f3dccb 100644
--- a/indoteknik_api/models/sale_order.py
+++ b/indoteknik_api/models/sale_order.py
@@ -4,11 +4,52 @@ from odoo import models
class SaleOrder(models.Model):
_inherit = 'sale.order'
- def api_v1_single_response(self, sale_order):
+ 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
+ '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',
}
+ if sale_order.state == 'cancel':
+ data['status'] = 'cancel'
+ if sale_order.state in ['draft', 'sent']:
+ data['status'] = 'draft'
+ if sale_order.approval_status in ['pengajuan1', 'pengajuan2']:
+ data['status'] = 'waiting'
+ if sale_order.state == 'sale':
+ data['status'] = 'sale'
+ for picking in sale_order.picking_ids:
+ if picking.state == 'assigned':
+ data['status'] = 'shipping'
+ if sale_order.state == 'done':
+ data['status'] = 'done'
+
+ if context:
+ if context == 'with_detail':
+ res_users = self.env['res.users']
+ data_with_detail = {
+ 'payment_term': sale_order.payment_term_id.name or '',
+ 'date_order': self.env['rest.api'].datetime_to_str(sale_order.date_order, '%d/%m/%Y %H:%M:%S'),
+ 'products': [],
+ 'address': {
+ '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)
+ },
+ 'invoices': []
+ }
+ for line in sale_order.order_line:
+ product = self.env['product.product'].api_single_response(line.product_id)
+ product['quantity'] = line.product_uom_qty
+ data_with_detail['products'].append(product)
+ for invoice in sale_order.invoice_ids:
+ if invoice.state == 'posted':
+ data_with_detail['invoices'].append(self.env['account.move'].api_v1_single_response(invoice))
+ data.update(data_with_detail)
return data
diff --git a/indoteknik_custom/models/__init__.py b/indoteknik_custom/models/__init__.py
index c6fb7d4f..121bd0f4 100755
--- a/indoteknik_custom/models/__init__.py
+++ b/indoteknik_custom/models/__init__.py
@@ -46,3 +46,4 @@ from . import x_partner_purchase_order
from . import x_product_tags
from . import website_ads
from . import leads_monitoring
+from . import midtrans
diff --git a/indoteknik_custom/models/account_move.py b/indoteknik_custom/models/account_move.py
index 54e51dcf..78fa2ddf 100644
--- a/indoteknik_custom/models/account_move.py
+++ b/indoteknik_custom/models/account_move.py
@@ -21,8 +21,8 @@ class AccountMove(models.Model):
def action_post(self):
res = super(AccountMove, self).action_post()
- if not self.env.user.is_accounting:
- raise UserError('Hanya Accounting yang bisa Posting')
+ # if not self.env.user.is_accounting:
+ # raise UserError('Hanya Accounting yang bisa Posting')
return res
@api.onchange('date_kirim_tukar_faktur')
diff --git a/indoteknik_custom/models/dunning_run.py b/indoteknik_custom/models/dunning_run.py
index ee0669ca..98689550 100644
--- a/indoteknik_custom/models/dunning_run.py
+++ b/indoteknik_custom/models/dunning_run.py
@@ -23,6 +23,7 @@ class DunningRun(models.Model):
date_terima_tukar_faktur = fields.Date(string='Terima Faktur')
shipper_faktur_id = fields.Many2one('delivery.carrier', string='Shipper Faktur')
is_validated = fields.Boolean(string='Validated')
+ notification = fields.Char(string='Notification')
def copy_date_faktur(self):
if not self.is_validated:
@@ -51,12 +52,14 @@ class DunningRun(models.Model):
invoice.invoice_date_due = due_date
if not invoice.shipper_faktur_id:
invoice.shipper_faktur_id = self.shipper_faktur_id
+ self.notification = 'Berhasil copy tanggal terima faktur ke setiap invoice %s' % self.date_terima_tukar_faktur
def validate_dunning(self):
if not self.dunning_line:
raise UserError('Dunning Line masih kosong, generate dulu')
else:
self.is_validated = True
+ self.notification = 'Jangan lupa klik Copy Date jika sudah ada tanggal kirim / tanggal terima faktur'
def generate_dunning_line(self):
if self.is_validated:
diff --git a/indoteknik_custom/models/midtrans.py b/indoteknik_custom/models/midtrans.py
new file mode 100644
index 00000000..76dee447
--- /dev/null
+++ b/indoteknik_custom/models/midtrans.py
@@ -0,0 +1,38 @@
+from odoo import fields, models, api
+import logging
+
+_logger = logging.getLogger(__name__)
+
+
+class MidtransNotification(models.Model):
+ _name = 'midtrans.notification'
+
+ json_raw = fields.Char(string='JSON Raw Text')
+ sale_order_id = fields.Many2one('sale.order', string='Sales Order')
+ payment_status = fields.Selection([
+ ('pending', 'Pending'),
+ ('capture', 'Capture'),
+ ('settlement', 'Settlement'),
+ ('deny', 'Deny'),
+ ('cancel', 'Cancel'),
+ ('expire', 'Expire'),
+ ('failure', 'Failure'),
+ ('refund', 'Refund'),
+ ('chargeback', 'Chargeback'),
+ ('partial_refund', 'Partial Refund'),
+ ('partial_chargeback', 'Partial Chargeback'),
+ ('authorize', 'Authorize'),
+ ], string='Payment Status',
+ help='Payment Gateway Status / Midtrans / Web, https://docs.midtrans.com/en/after-payment/status-cycle')
+
+
+class MidtransRecurring(models.Model):
+ _name = 'midtrans.recurring'
+
+ json_raw = fields.Char(string='JSON Raw Text')
+
+
+class MidtransAccount(models.Model):
+ _name = 'midtrans.account'
+
+ json_raw = fields.Char(string='JSON Raw Text')
diff --git a/indoteknik_custom/models/user_activity_log.py b/indoteknik_custom/models/user_activity_log.py
index 32b389a1..ef801ca5 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&amp;hl=id&amp;z=15&amp;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=45, 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/security/ir.model.access.csv b/indoteknik_custom/security/ir.model.access.csv
index d469aa1e..83d9e2ed 100755
--- a/indoteknik_custom/security/ir.model.access.csv
+++ b/indoteknik_custom/security/ir.model.access.csv
@@ -27,4 +27,7 @@ access_website_content,access.website.content,model_website_content,,1,1,1,1
access_invoice_reklas,access.invoice.reklas,model_invoice_reklas,,1,1,1,1
access_custom_mail_marketing,access.custom.mail.marketing,model_custom_mail_marketing,,1,1,1,1
access_website_ads,access.website.ads,model_website_ads,,1,1,1,1
-access_leads_monitoring,access.leads.monitoring,model_leads_monitoring,,1,1,1,1 \ No newline at end of file
+access_leads_monitoring,access.leads.monitoring,model_leads_monitoring,,1,1,1,1
+access_midtrans_notification,access.midtrans.notification,model_midtrans_notification,,1,1,1,1
+access_midtrans_recurring,access.midtrans.recurring,model_midtrans_recurring,,1,1,1,1
+access_midtrans_account,access.midtrans.account,model_midtrans_account,,1,1,1,1 \ No newline at end of file
diff --git a/indoteknik_custom/views/dunning_run.xml b/indoteknik_custom/views/dunning_run.xml
index 6343a79b..cae9cc32 100644
--- a/indoteknik_custom/views/dunning_run.xml
+++ b/indoteknik_custom/views/dunning_run.xml
@@ -63,6 +63,7 @@
<field name="number"/>
<field name="partner_id"/>
<field name="dunning_date"/>
+ <field name="notification" readonly="1"/>
</group>
<group>
<field name="is_validated" readonly="1"/>
diff --git a/indoteknik_custom/views/user_activity_log.xml b/indoteknik_custom/views/user_activity_log.xml
index db242505..91c14b4d 100755
--- a/indoteknik_custom/views/user_activity_log.xml
+++ b/indoteknik_custom/views/user_activity_log.xml
@@ -4,9 +4,11 @@
<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="ip_location_country"/>
<field name="url" widget="url"/>
<field name="res_user_id"/>
<field name="email"/>
@@ -18,7 +20,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 +29,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>