Commit 86c89c5a by aa.gusti

penambahan portal buat ppat????

1 parent 3828f9e8
......@@ -25,8 +25,10 @@ Memudahkan dalam mengelola tagihan kepada wajib pajak atau wajib retribusi
'views/sales.xml',
'views/menus.xml',
'demo/bphtb.sales.csv',
'views/portal_templates.xml',
'report/sspd_format_template.xml',
],
'demo': [
'demo/bphtb.sales.csv'
......
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
import base64
from collections import OrderedDict
from datetime import datetime
from odoo import http, _
from odoo.addons.portal.controllers.portal import CustomerPortal, pager as portal_pager
from odoo import http
from odoo.exceptions import AccessError, MissingError
from collections import OrderedDict
from odoo.http import request
from odoo.http import request, Response
from odoo.tools import image_process
from odoo.tools.translate import _
from odoo.addons.portal.controllers.portal import (
get_records_pager, pager as portal_pager, CustomerPortal)
from odoo.addons.web.controllers.main import Binary
STATE = ['draft', 'confirmed', 'canceled']
class PortalAccount(CustomerPortal):
class CustomerPortal(CustomerPortal):
def _prepare_home_portal_values(self, counters):
values = super()._prepare_home_portal_values(counters)
if 'invoice_count' in counters:
invoice_count = request.env['account.move'].search_count(self._get_pad_domain()) \
if request.env['account.move'].check_access_rights('read', raise_exception=False) else 0
values['invoice_count'] = invoice_count
if 'bphtb_count' in counters:
values['bphtb_count'] = request.env['bphtb.sales'].search_count([
('state', 'in', STATE)
]) if request.env['bphtb.sales'].check_access_rights(
'read', raise_exception=False) else 0
return values
# ------------------------------------------------------------
# My pad
# ------------------------------------------------------------
def _bphtb_sales_get_page_view_values(self, sales, access_token, **kwargs):
def resize_to_48(b64source):
if not b64source:
b64source = base64.b64encode(Binary.placeholder())
return image_process(b64source, size=(48, 48))
def _invoice_get_page_view_values(self, invoice, access_token, **kwargs):
values = {
'page_name': 'invoice',
'invoice': invoice,
'sales': sales,
'resize_to_48': resize_to_48,
}
return self._get_page_view_values(invoice, access_token, values, 'my_pad_history', False, **kwargs)
def _get_pad_domain(self):
return [
('move_type', 'in', ('out_invoice', 'out_refund', 'in_invoice', 'in_refund', 'out_receipt', 'in_receipt'))]
return self._get_page_view_values(sales, access_token, values,
'my_bphtbs_history', False, **kwargs)
@http.route(['/my/pad', '/my/pad/page/<int:page>'], type='http', auth="user", website=True)
def portal_my_pad(self, page=1, date_begin=None, date_end=None, sortby=None, filterby=None, **kw):
@http.route(['/my/bphtb', '/my/bphtb/page/<int:page>'], type='http', auth="user", website=True)
def portal_my_bphtb_saless(self, page=1, date_begin=None, date_end=None, sortby=None, filterby=None, **kw):
values = self._prepare_portal_layout_values()
AccountInvoice = request.env['account.move']
BphtbSales = request.env['bphtb.sales']
domain = self._get_pad_domain()
domain = []
if date_begin and date_end:
domain += [('create_date', '>', date_begin), ('create_date', '<=', date_end)]
searchbar_sortings = {
'date': {'label': _('Date'), 'order': 'invoice_date desc'},
'duedate': {'label': _('Due Date'), 'order': 'invoice_date_due desc'},
'name': {'label': _('Reference'), 'order': 'name desc'},
'state': {'label': _('Status'), 'order': 'state'},
'date': {'label': _('Newest'), 'order': 'create_date desc, id desc'},
'name': {'label': _('Name'), 'order': 'name asc, id asc'},
'owed': {'label': _('Total'), 'order': 'owed desc, id desc'},
}
# default sort by order
# default sort by value
if not sortby:
sortby = 'date'
order = searchbar_sortings[sortby]['order']
searchbar_filters = {
'all': {'label': _('All'), 'domain': []},
'pad': {'label': _('pad'), 'domain': [('move_type', '=', ('out_invoice', 'out_refund'))]},
'bills': {'label': _('Bills'), 'domain': [('move_type', '=', ('in_invoice', 'in_refund'))]},
'all': {'label': _('All'), 'domain': [('state', 'in', STATE)]},
'draft': {'label': _('Draft'), 'domain': [('state', '=', 'draft')]},
'confirmed': {'label': _('Confirmed'), 'domain': [('state', '=', 'confirmed')]},
'canceled': {'label': _('Canceled'), 'domain': [('state', '=', 'canceled')]},
}
# default filter by value
if not filterby:
filterby = 'all'
domain += searchbar_filters[filterby]['domain']
if date_begin and date_end:
domain += [('create_date', '>', date_begin), ('create_date', '<=', date_end)]
# count for pager
invoice_count = AccountInvoice.search_count(domain)
# pager
bphtb_count = BphtbSales.search_count(domain)
# make pager
pager = portal_pager(
url="/my/pad",
url_args={'date_begin': date_begin, 'date_end': date_end, 'sortby': sortby},
total=invoice_count,
url="/my/bphtb",
url_args={
'date_begin': date_begin, 'date_end': date_end,
'sortby': sortby, 'filterby': filterby
},
total=bphtb_count,
page=page,
step=self._items_per_page
)
# content according to pager and archive selected
pad = AccountInvoice.search(domain, order=order, limit=self._items_per_page, offset=pager['offset'])
request.session['my_pad_history'] = pad.ids[:100]
# search the bphtb orders to display, according to the pager data
saless = BphtbSales.search(
domain,
order=order,
limit=self._items_per_page,
offset=pager['offset']
)
request.session['my_bphtbs_history'] = saless.ids[:100]
values.update({
'date': date_begin,
'pad': pad,
'page_name': 'invoice',
'saless': saless,
'page_name': 'bphtb',
'pager': pager,
'default_url': '/my/pad',
'searchbar_sortings': searchbar_sortings,
'sortby': sortby,
'searchbar_filters': OrderedDict(sorted(searchbar_filters.items())),
'filterby': filterby,
'default_url': '/my/bphtb',
})
return request.render("account.portal_my_pad", values)
return request.render("bphtb_kab.portal_my_bphtb_saless", values)
@http.route(['/my/pad/<int:invoice_id>'], type='http', auth="public", website=True)
def portal_my_invoice_detail(self, invoice_id, access_token=None, report_type=None, download=False, **kw):
@http.route(['/my/bphtb/<int:sales_id>'], type='http', auth="public", website=True)
def portal_my_bphtb_sales(self, sales_id=None, access_token=None, **kw):
try:
invoice_sudo = self._document_check_access('account.move', invoice_id, access_token)
order_sudo = self._document_check_access('bphtb.sales', sales_id,
access_token=access_token)
except (AccessError, MissingError):
return request.redirect('/my')
report_type = kw.get('report_type')
if report_type in ('html', 'pdf', 'text'):
return self._show_report(model=invoice_sudo, report_type=report_type, report_ref='account.account_pad',
download=download)
values = self._invoice_get_page_view_values(invoice_sudo, access_token, **kw)
acquirers = values.get('acquirers')
if acquirers:
country_id = values.get('partner_id') and values.get('partner_id')[0].country_id.id
values['acq_extra_fees'] = acquirers.get_acquirer_extra_fees(invoice_sudo.amount_residual,
invoice_sudo.currency_id, country_id)
return request.render("account.portal_invoice_page", values)
# ------------------------------------------------------------
# My Home
# ------------------------------------------------------------
def details_form_validate(self, data):
error, error_message = super(PortalAccount, self).details_form_validate(data)
# prevent VAT/name change if pad exist
partner = request.env['res.users'].browse(request.uid).partner_id
if not partner.can_edit_vat():
if 'vat' in data and (data['vat'] or False) != (partner.vat or False):
error['vat'] = 'error'
error_message.append(
_('Changing VAT number is not allowed once pad have been issued for your account. Please contact '
'us directly for this operation.'))
if 'name' in data and (data['name'] or False) != (partner.name or False):
error['name'] = 'error'
error_message.append(
_('Changing your name is not allowed once pad have been issued for your account. Please contact '
'us directly for this operation.'))
if 'company_name' in data and (data['company_name'] or False) != (partner.company_name or False):
error['company_name'] = 'error'
error_message.append(
_('Changing your company name is not allowed once pad have been issued for your account. Please contact us directly for this operation.'))
return error, error_message
return self._show_report(model=order_sudo, report_type=report_type,
report_ref='bphtb_kab.action_report_bphtb_sspd',
download=kw.get('download'))
confirm_type = kw.get('confirm')
if confirm_type == 'reminder':
order_sudo.confirm_reminder_mail(kw.get('confirmed_date'))
if confirm_type == 'reception':
order_sudo._confirm_reception_mail()
values = self._bphtb_sales_get_page_view_values(order_sudo, access_token, **kw)
update_date = kw.get('update')
if order_sudo.company_id:
values['res_company'] = order_sudo.company_id
if update_date == 'True':
return request.render("bphtb_kab.portal_my_bphtb_sales_update_date", values)
return request.render("bphtb_kab.portal_my_bphtb_sales", values)
@http.route(['/my/bphtb/<int:sales_id>/update'], type='http',
methods=['POST'], auth="public", website=True)
def portal_my_bphtb_sales_update_dates(self, sales_id=None, access_token=None, **kw):
"""User update scheduled date on bphtb order line.
"""
try:
order_sudo = self._document_check_access('bphtb.sales', sales_id, access_token=access_token)
except (AccessError, MissingError):
return request.redirect('/my')
updated_dates = []
for id_str, date_str in kw.items():
try:
line_id = int(id_str)
except ValueError:
return request.redirect(order_sudo.get_portal_url())
order_sudo.write({
"date": datetime.strptime(date_str, '%Y-%m-%d'),
"state": "confirmed"
})
# line = order_sudo.order_line.filtered(lambda l: l.id == line_id)
# if not line:
# return request.redirect(order_sudo.get_portal_url())
# try:
# updated_date = line._convert_to_middle_of_day(
# datetime.strptime(date_str, '%Y-%m-%d'))
# except ValueError:
# continue
#
# updated_dates.append((line, updated_date))
#
# if updated_dates:
# order_sudo._update_date_planned_for_lines(updated_dates)
return Response(status=204)
......@@ -14,7 +14,6 @@ _logger = logging.getLogger(__name__)
class BphtbSales(models.Model):
_name = 'bphtb.sales'
_description = 'Transaksi BPHTB'
# code = fields.Char(index=True, string='Code')
_inherit = ['portal.mixin', 'mail.thread', 'mail.activity.mixin', 'sequence.mixin']
name = fields.Char(string='Number', copy=False, compute='_compute_name', readonly=False, store=True, index=True,
tracking=True)
......@@ -128,7 +127,7 @@ class BphtbSales(models.Model):
disc_amount = fields.Float()
payment = fields.Float(readonly=True,
states={'draft': [('readonly', False)]}, )
owed = fields.Float(compute="_compute_owed")
owed = fields.Float(compute="_compute_owed", store=True)
typ = fields.Selection([
('sspd', 'SSPD'),
('kb', 'SKPD KB'),
......@@ -155,6 +154,8 @@ class BphtbSales(models.Model):
default=lambda self: self.env.company.id
if not self.company_id else False)
district_id = fields.Many2one('res.district', related='company_id.district_id', store=True)
wp_ids = fields.Many2many('res.partner', readonly=True,
states={'draft': [('readonly', False)]}, )
def _my_check_method(self, cr, uid, ids, context=None):
# Your code goes here
......@@ -515,3 +516,9 @@ class BphtbSales(models.Model):
# if self.journal_id.refund_sequence and self.move_type in ('out_refund', 'in_refund'):
# starting_sequence = "R" + starting_sequence
return starting_sequence
#Portal Area
def _compute_access_url(self):
super(BphtbSales, self)._compute_access_url()
for bphtb in self:
bphtb.access_url = '/my/bphtb/%s' % (bphtb.id)
\ No newline at end of file
......@@ -107,7 +107,6 @@ class SequenceMixin(models.AbstractModel):
(self._sequence_yearly_regex, 'year', ['seq', 'year']),
(self._sequence_fixed_regex, 'never', ['seq']),
]:
_logger.info(f"{regex}, {ret_val}, {requirements} ")
match = re.match(regex, name or '')
if match:
groupdict = match.groupdict()
......@@ -207,7 +206,6 @@ class SequenceMixin(models.AbstractModel):
regex = self._sequence_yearly_regex
elif sequence_number_reset == 'month':
regex = self._sequence_monthly_regex
_logger.info(f'{regex} {sequence_number_reset}')
format_values = re.match(regex, previous).groupdict()
format_values['seq_length'] = len(format_values['seq'])
format_values['year_length'] = len(format_values.get('year', ''))
......
......@@ -9,3 +9,4 @@
"access_bphtb_sales_admin","access.bphtb.sales.admin","model_bphtb_sales","base.group_system",1,1,1,1
"access_bphtb_sales_bphtb_admin","access.bphtb.sales.bphtb.admin","model_bphtb_sales","group_bphtb_admin",1,1,1,1
"access_bphtb_sales_bphtb_ppat","access.bphtb.sales.bphtb.ppt","model_bphtb_sales","group_bphtb_ppat",1,1,1,0
"access_bphtb_sales_portal","access.bphtb.sales.portal","model_bphtb_sales","base.group_portal",1,1,1,0
......@@ -25,6 +25,18 @@
<field name="perm_write" eval="True"/>
<field name="perm_unlink" eval="False"/>
</record>
<record model="ir.rule" id="bphtb_sales_portal_rule">
<field name="name">bphtb.sales portal</field>
<field name="model_id" ref="model_bphtb_sales"/>
<field name="groups" eval="[4,ref('base.group_portal')]"/>
<field name="domain_force">[('ppat_id', 'child_of', user.commercial_partner_id.id)]</field>
<field name="perm_read" eval="True"/>
<field name="perm_create" eval="False"/>
<field name="perm_write" eval="False"/>
<field name="perm_unlink" eval="False"/>
</record>
<!-- <record model="ir.rule" id="bphtb_sales_edit_disable">-->
<!-- <field name="name">bphtb_sales_edit_disable</field>-->
......
......@@ -9,6 +9,13 @@
<xpath expr="//field[@name='type']" position="attributes">
<attribute name="invisible">True</attribute>
</xpath>
<xpath expr="//field[@name='category_id']" position="replace"/>
<xpath expr="//field[@name='function']" position="replace"/>
<xpath expr="//field[@name='title']" position="replace"/>
<xpath expr="//page[@name='sales_purchases']" position="attributes">
<attribute name="invisible">1</attribute>
</xpath>
</field>
</record>
<record id="action_ppat_config_bphtb_kab" model="ir.actions.act_window">
......
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<template id="portal_my_home_menu_bphtb" name="Portal layout : bphtb menu entries"
inherit_id="portal.portal_breadcrumbs" priority="25">
<xpath expr="//ol[hasclass('o_portal_submenu')]" position="inside">
<li t-if="page_name == 'bphtb' or bphtb_sales"
t-attf-class="breadcrumb-item #{'active ' if not bphtb_sales else ''}">
<a t-if="bphtb_sales" t-attf-href="/my/bphtb?{{ keep_query() }}">Bphtb Transaction</a>
<t t-else="">Bphtb Transaction</t>
</li>
<li t-if="bphtb_sales" class="breadcrumb-item active">
<t t-esc="bphtb_sales.name"/>
</li>
</xpath>
</template>
<template id="portal_my_home_bphtb" name="Show Bphtb Transaction" customize_show="True"
inherit_id="portal.portal_my_home" priority="25">
<xpath expr="//div[hasclass('o_portal_docs')]" position="inside">
<t t-call="portal.portal_docs_entry">
<t t-set="title">Bphtb Transaction</t>
<t t-set="url" t-value="'/my/bphtb'"/>
<t t-set="placeholder_count" t-value="'bphtb_count'"/>
</t>
</xpath>
</template>
<template id="portal_my_bphtb_saless" name="Portal: My Bphtb Transaction">
<t t-call="portal.portal_layout">
<t t-set="breadcrumbs_searchbar" t-value="True"/>
<t t-call="portal.portal_searchbar"/>
<t t-if="saless" t-call="portal.portal_table">
<thead>
<tr class="active">
<th>Bphtb Transaction #</th>
<th>NOP</th>
<th>Buyer</th>
<th>Seller</th>
<th class="text-right">Date</th>
<th></th>
<th class="text-right">Total</th>
</tr>
</thead>
<tbody>
<t t-foreach="saless" t-as="sales">
<tr>
<td>
<a t-att-href="sales.get_portal_url()">
<t t-esc="sales.name"/>
</a>
</td>
<td>
<span t-field="sales.nop"/>
</td>
<td>
<span t-field="sales.wp_id"/>
</td>
<td>
<span t-field="sales.seller_id"/>
</td>
<td class="text-right">
<span t-field="sales.date"/>
</td>
<td>
<!-- <t t-if="sales.invoice_status == 'to invoice'">-->
<!-- <span class="badge badge-info"><i class="fa fa-fw fa-file-text"/> Waiting for Bill</span>-->
<!-- </t>-->
<t t-if="sales.state == 'draft'">
<span class="badge badge-secondary">
<i class="fa fa-fw fa-firstdraft"/>
Draft
</span>
</t>
<t t-if="sales.state == 'confirmed'">
<span class="badge badge-primary">
<i class="fa fa-fw fa-check-circle"/>
Draft
</span>
</t>
<t t-if="sales.state == 'cancel'">
<span class="badge badge-secondary">
<i class="fa fa-fw fa-remove"/>
Cancelled
</span>
</t>
</td>
<td class="text-right">
<span t-field="sales.owed"/>
</td>
</tr>
</t>
</tbody>
</t>
</t>
</template>
<template id="portal_my_bphtb_sales" name="Portal: My Purchase Order">
<t t-call="portal.portal_layout">
<t t-set="bphtb_sales" t-value="sales"/>
<t t-set="o_portal_fullwidth_alert" groups="bphtb_kab.group_bphtb_admin">
<t t-call="portal.portal_back_in_edit_mode">
<t t-set="backend_url"
t-value="'/web#return_label=Website&amp;model=%s&amp;id=%s&amp;action=%s&amp;view_type=form' % (bphtb_sales._name, bphtb_sales.id, bphtb_sales.id)"/>
</t>
</t>
<div id="optional_placeholder"></div>
<div class="container">
<div class="row mt16 o_portal_bphtb_sidebar">
<!-- Sidebar -->
<t t-call="portal.portal_record_sidebar">
<t t-set="classes" t-value="'col-lg-auto d-print-none'"/>
<t t-set="title">
<h2 class="mb-0">
<b t-field="sales.owed" data-id="owed"/>
</h2>
</t>
<t t-set="entries">
<ul class="list-group list-group-flush flex-wrap flex-row flex-lg-column">
<li class="list-group-item flex-grow-1">
<div class="o_download_pdf btn-toolbar flex-sm-nowrap">
<div class="btn-group flex-grow-1 mr-1 mb-1">
<a class="btn btn-secondary btn-block o_download_btn"
t-att-href="bphtb_sales.get_portal_url(report_type='pdf', download=True)"
title="Download">
<i class="fa fa-download"/>
Download
</a>
</div>
<div class="btn-group flex-grow-1 mb-1">
<a class="btn btn-secondary btn-block o_print_btn o_portal_invoice_print"
t-att-href="bphtb_sales.get_portal_url(report_type='pdf')"
id="print_invoice_report" title="Print" target="_blank">
<i class="fa fa-print"/>
Print
</a>
</div>
</div>
</li>
<li t-if="bphtb_sales.wp_id" class="list-group-item flex-grow-1">
<div class="small mb-1">
<strong class="text-muted">Buyer</strong>
</div>
<div class="row flex-nowrap">
<div class="col flex-grow-0 pr-2">
<img class="rounded-circle mr4 float-left o_portal_contact_img"
t-if="bphtb_sales.wp_id.image_1024"
t-att-src="image_data_uri(bphtb_sales.wp_id.image_1024)"
alt="Buyer"/>
<img class="rounded-circle mr4 float-left o_portal_contact_img"
t-if="not bphtb_sales.wp_id.image_1024"
src="/web/static/src/img/placeholder.png" alt="Buyer"/>
</div>
<div class="col pl-0" style="min-width: 150px">
<span t-field="bphtb_sales.wp_id"
t-options='{"widget": "contact", "fields": ["name", "phone"], "no_marker": True}'/>
<a href="#discussion" class="small">
<i class="fa fa-comment"></i>
Send message
</a>
</div>
</div>
</li>
<li t-if="bphtb_sales.seller_id" class="list-group-item flex-grow-1">
<div class="small mb-1">
<strong class="text-muted">Seller</strong>
</div>
<div class="row flex-nowrap">
<div class="col flex-grow-0 pr-2">
<img class="rounded-circle mr4 float-left o_portal_contact_img"
t-if="bphtb_sales.seller_id.image_1024"
t-att-src="image_data_uri(bphtb_sales.seller_id.image_1024)"
alt="Seller"/>
<img class="rounded-circle mr4 float-left o_portal_contact_img"
t-if="not bphtb_sales.seller_id.image_1024"
src="/web/static/src/img/placeholder.png" alt="Seller"/>
</div>
<div class="col pl-0" style="min-width: 150px">
<span t-field="bphtb_sales.seller_id"
t-options='{"widget": "contact", "fields": ["name", "phone"], "no_marker": True}'/>
<a href="#discussion" class="small">
<i class="fa fa-comment"></i>
Send message
</a>
</div>
</div>
</li>
</ul>
</t>
</t>
<div class=" col-lg col-12 justify-content-end w-100">
<div class="card pb-5">
<div class="card-header bg-white pb-1">
<div class="row">
<div class="col-lg-12">
<h2 class="font-weight-normal">
<t t-if="sales.state in ['draft', 'sent']">Draft</t>
<t t-if="sales.state in ['confirmed']">Confirmed</t>
<t t-if="sales.state in ['canceled']">Canceled</t>
<span class="font-italic" t-esc="sales.name"/>
</h2>
</div>
</div>
</div>
<div class="card-body">
<div class="mb-4">
<strong class="d-block mb-1">From:</strong>
<address t-field="sales.company_id.partner_id"
t-options='{"widget": "contact", "fields": ["address", "name"], "no_marker": True}'/>
<strong>Create Date:</strong>
<span t-field="sales.create_date" t-options='{"widget": "date"}'/>
<br/>
<div t-att-class="'d-inline'">
<strong>Confirmation Date:</strong>
<span t-if="sales.state!='draft'" class="ml-1" t-field="sales.date"
t-options='{"widget": "date"}'/>
<div t-att-class="'d-inline'" t-if="sales.state=='draft'">
<form t-attf-action="/my/bphtb/#{sales.id}/update?access_token=#{sales.access_token}"
method="post">
<input type="hidden" name="csrf_token"
t-att-value="request.csrf_token()"/>
<div class="input-group date col-sm-3">
<input type="text"
class="form-control datetimepicker-input o-bphtb-datetimepicker"
t-attf-id="datetimepicker_#{sales.id}"
t-att-name="sales.id"
data-toggle="datetimepicker"
data-date-format="YYYY-MM-DD"
t-attf-data-target="#datetimepicker_#{sales.id}"/>
<button>Confirm</button>
</div>
</form>
</div>
</div>
</div>
<h3 class="font-weight-normal">Objek Pajak</h3>
<table class="table table-sm">
<tbody>
<tr>
<td>NOP</td>
<td>
<span t-field="sales.nop"/>
<span t-field="sales.tax_year"/>
</td>
<td></td>
</tr>
<tr>
<td>
<strong>Objek</strong>
</td>
<td class="text-right">
<strong>Luas</strong>
</td>
<td class="text-right">
<strong>NJOP</strong>
</td>
</tr>
<tr>
<td>Bumi</td>
<td class="text-right">
<span t-field="sales.luas_bumi"/>
</td>
<td class="text-right">
<span t-field="sales.njop_bumi"/>
</td>
</tr>
<tr>
<td>Bangunan</td>
<td class="text-right">
<span t-field="sales.luas_bng"/>
</td>
<td class="text-right">
<span t-field="sales.njop_bng"/>
</td>
</tr>
<tr>
<td>Bumi Bersama</td>
<td class="text-right">
<span t-field="sales.luas_bumi_bersama"/>
</td>
<td class="text-right">
<span t-field="sales.njop_bumi_bersama"/>
</td>
</tr>
<tr>
<td>Bangunan Bersama</td>
<td class="text-right">
<span t-field="sales.luas_bng_bersama"/>
</td>
<td class="text-right">
<span t-field="sales.njop_bng_bersama"/>
</td>
</tr>
<tr>
<td colspan="2" class="text-right">
<strong>NJOP</strong>
</td>
<td class="text-right">
<strong>
<span t-field="sales.njop"/>
</strong>
</td>
</tr>
</tbody>
</table>
<h3 class="font-weight-normal">Perhitungan</h3>
<table class="table table-sm">
<tr>
<td>Jenis Perolehan</td>
<td>
<span t-field="sales.jenis_id"/>
</td>
</tr>
<tr>
<td>NPOP</td>
<td class="text-right">
<span t-field="sales.npop"/>
</td>
</tr>
<tr>
<td>Dasar Perhitungan</td>
<td class="text-right">
<span t-field="sales.basic_calc"/>
</td>
</tr>
<tr>
<td>NJOPTKP</td>
<td class="text-right">
<span t-field="sales.min_omzet"/>
</td>
</tr>
<tr>
<td>NJKP</td>
<td class="text-right">
<span t-field="sales.npopkp"/>
</td>
</tr>
<tr>
<td>Tarif (%)</td>
<td class="text-right">
<span t-field="sales.rate"/>
</td>
</tr>
<tr>
<td>Pokok</td>
<td class="text-right">
<span t-field="sales.basic"/>
</td>
</tr>
<tr>
<td>Denda</td>
<td class="text-right">
<span t-field="sales.fine"/>
</td>
</tr>
<tr>
<td>Discount (%)</td>
<td class="text-right">
<span t-field="sales.disc"/>
</td>
</tr>
<tr>
<td>Pembayaran</td>
<td class="text-right">
<span t-field="sales.payment"/>
</td>
</tr>
<tr>
<td>
<strong>Terhutang</strong>
</td>
<td class="text-right">
<strong>
<span t-field="sales.owed"/>
</strong>
</td>
</tr>
</table>
</div>
</div>
<div id="bphtb_sales_communication" class="mt-4">
<h2>History</h2>
<t t-call="portal.message_thread">
<t t-set="object" t-value="bphtb_sales"/>
</t>
</div>
</div>
</div>
</div>
<div class="oe_structure mb32"/>
</t>
</template>
<template id="portal_my_bphtb_sales_update_date" name="Portal: My Purchase Order Update Dates"
inherit_id="bphtb_kab.portal_my_bphtb_sales" primary="True">
<xpath expr="//div[hasclass('card-body')]" position="replace">
<div class="card-body">
<div class="mb-4">
<!-- <strong>Confirmation Date:</strong> <span t-field="sales.date_approve" t-options='{"widget": "date"}'/><br/>-->
<!-- <div t-att-class="'d-inline' if sales.date_planned else 'd-none'">-->
<!-- <strong>Receipt Date:</strong><span class="ml-1" t-field="sales.date_planned" t-options='{"widget": "date"}'/>-->
<!-- </div>-->
</div>
<h3 class="font-weight-normal">Pricing</h3>
<table class="table table-sm">
<thead class="bg-100">
<tr>
<th>Products</th>
<th class="text-right d-none d-sm-table-cell">Unit Price</th>
<th class="text-right">Quantity</th>
<th class="text-right">Scheduled Date</th>
<th class="text-right" style="color:#3aadaa">
<strong>Update Dates Here</strong>
</th>
<th class="text-right">Subtotal</th>
</tr>
</thead>
<tbody>
<t t-foreach="sales.sales_line" t-as="ol">
<tr>
<td>
<img t-att-src="image_data_uri(resize_to_48(ol.product_id.image_1024))"
alt="Product" class="d-none d-lg-inline"/>
<span t-esc="ol.name"/>
</td>
<td class="text-right d-none d-sm-table-cell">
<span t-field="ol.price_unit"
t-options='{"widget": "monetary", "display_currency": sales.currency_id}'/>
</td>
<td class="text-right">
<span t-esc="ol.product_qty"/>
</td>
<td class="text-right">
<span t-esc="ol.date_planned.date()"/>
</td>
<td class="text-right">
<form t-attf-action="/my/bphtb/#{sales.id}/update?access_token=#{sales.access_token}"
method="post">
<input type="hidden" name="csrf_token" t-att-value="request.csrf_token()"/>
<div class="container">
<div class="form-group">
<div class="input-group date">
<input type="text"
class="form-control datetimepicker-input o-bphtb-datetimepicker"
t-attf-id="datetimepicker_#{ol.id}" t-att-name="ol.id"
data-toggle="datetimepicker" data-date-format="YYYY-MM-DD"
t-attf-data-target="#datetimepicker_#{ol.id}"/>
</div>
</div>
</div>
</form>
</td>
<td class="text-right">
<span t-field="ol.price_subtotal"
t-options='{"widget": "monetary", "display_currency": sales.currency_id}'/>
</td>
</tr>
</t>
</tbody>
</table>
<div class="row">
<div class="col-sm-7 col-md-5 ml-auto">
<table class="table table-sm">
<tbody>
<tr>
<td>
<strong>Untaxed Amount:</strong>
</td>
<td class="text-right">
<span t-field="sales.amount_untaxed"
t-options='{"widget": "monetary", "display_currency": sales.currency_id}'/>
</td>
</tr>
<tr>
<td>
<strong>Taxes:</strong>
</td>
<td class="text-right">
<span t-field="sales.amount_tax"
t-options='{"widget": "monetary", "display_currency": sales.currency_id}'/>
</td>
</tr>
<tr>
<td>
<strong>Total:</strong>
</td>
<td class="text-right">
<span t-field="sales.owed"
t-options='{"widget": "monetary", "display_currency": sales.currency_id}'/>
</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</xpath>
</template>
</odoo>
\ No newline at end of file
......@@ -61,6 +61,7 @@
<field name="nop" string="NOP"/>
<field name="tax_year" string="Tahun"/>
<field name="jenis_id" string="Jenis"/>
<field name="ppat_id" string="PPAT"/>
<field name="wp_id" string="Wajib Pajak"/>
<field name="owed" string="Terutang"/>
<field name="state" string="Status"/>
......@@ -166,8 +167,160 @@
<field name="wp_email" placeholder="ZIP" class="o_address_zip"/>
<field name="wp_phone" placeholder="ZIP" class="o_address_zip"/>
</group>
</group>
</page>
<page string="WP Lain" name="wp_others" autofocus="autofocus">
<field name="wp_ids" mode="kanban"
context="{'default_bphtb_sales_id': active_id,
'default_type': 'wp'}">
<kanban>
<field name="id"/>
<field name="color"/>
<field name="name"/>
<field name="identity_number"/>
<field name="title"/>
<field name="type"/>
<field name="email"/>
<field name="parent_id"/>
<field name="is_company"/>
<field name="function"/>
<field name="phone"/>
<field name="street"/>
<field name="street2"/>
<field name="zip"/>
<field name="district_id"/>
<field name="country_id"/>
<field name="mobile"/>
<field name="state_id"/>
<field name="image_128"/>
<field name="lang"/>
<!-- fields in form x2many view to diminish requests -->
<field name="comment"/>
<field name="display_name"/>
<templates>
<t t-name="kanban-box">
<t t-set="color" t-value="kanban_color(record.color.raw_value)"/>
<div t-att-class="color + (record.title.raw_value == 1 ? ' oe_kanban_color_alert' : '') + ' oe_kanban_global_click'">
<div class="o_kanban_image">
<img alt="Contact image" t-if="record.image_128.raw_value"
t-att-src="kanban_image('res.partner', 'image_128', record.id.raw_value)"/>
<t t-if="!record.image_128.raw_value">
<img alt="Delivery"
t-if="record.type.raw_value === 'delivery'"
t-att-src='_s + "/base/static/img/truck.png"'/>
<img alt="Invoice"
t-if="record.type.raw_value === 'invoice'"
t-att-src='_s + "/base/static/img/money.png"'/>
<t t-if="record.type.raw_value !== 'invoice' &amp;&amp; record.type.raw_value !== 'delivery'">
<img alt="Logo"
t-if="record.is_company.raw_value === true"
t-att-src='_s + "/base/static/img/company_image.png"'/>
<img alt="Avatar"
t-if="record.is_company.raw_value === false"
t-att-src='_s + "/base/static/img/avatar_grey.png"'/>
</t>
</t>
</div>
<div class="oe_kanban_details">
<field name="name"/>
<div t-if="record.identity_number.raw_value">
<field name="identity_number"/>
</div>
<div t-if="record.function.raw_value">
<field name="function"/>
</div>
<div t-if="record.email.raw_value">
<field name="email" widget="email"/>
</div>
<div t-if="record.type.raw_value != 'contact'">
<div>
<field name="zip"/>
<field name="city"/>
</div>
<field t-if="record.state_id.raw_value" name="state_id"/>
<field name="country_id"/>
</div>
<div t-if="record.phone.raw_value">Phone:
<t t-esc="record.phone.value"/>
</div>
<div t-if="record.mobile.raw_value">Mobile:
<t t-esc="record.mobile.value"/>
</div>
</div>
</div>
</t>
</templates>
</kanban>
<form string="Contact / Address">
<sheet>
<!-- parent_id and type fields needed in attrs in base_address_city module which overwrites
_fields_view_get() of partner. It would be better to put those fields there but the web client
dosen't support when a field is displayed several times in the same view.-->
<field name="type" required="1" widget="radio"
options="{'horizontal': true}" invisible="1"/>
<field name="parent_id" invisible="1"/>
<hr/>
<group col="12">
<group colspan="5">
<field name="name" string="Name"
attrs="{'required' : 1}"/>
<label for="street" string="Address"
attrs="{'required' : 1}"/>
<div>
<div class="o_address_format" name="div_address">
<field name="street" placeholder="Street..."
class="o_address_street"/>
<field name="street2" placeholder="Street 2..."
class="o_address_street"/>
<field name="village_id" class="o_address_street"
placeholder="Village"
options="{'no_open': True, 'no_create': True}"/>
<field name="sub_district_id" class="o_address_street"
placeholder="Sub District"
options="{'no_open': True, 'no_create': True}"/>
<field name="district_id" class="o_address_street"
placeholder="District"
options="{'no_open': True, 'no_create': True}"/>
<field name="state_id" class="o_address_state"
placeholder="State"
options="{'no_open': True, 'no_create': True}"
context="{'country_id': country_id, 'default_country_id': country_id, 'zip': zip}"/>
<field name="zip" placeholder="ZIP" class="o_address_zip"/>
<field name="country_id" placeholder="Country"
class="o_address_country"
options='{"no_open": True, "no_create": True}'/>
</div>
</div>
<field name="comment" placeholder="Internal notes..."/>
</group>
<group colspan="5">
<field name="email" widget="email"/>
<field name="phone" widget="phone"/>
<field name="mobile" widget="phone"/>
<field name="company_id" invisible="1"/>
<field name="identity_number" string="Identity Number"
attrs="{'required' : 1}"/>
<div>
<label for="identity_card" string="ID Card"/>
<field name="identity_card" widget="image"
nolabel="1" options="{'image_preview': 'image_128'}"
attrs="{'required' : 1}"/>
</div>
</group>
<group colspan="1">
<field name="image_1920" widget="image" class="oe_avatar"
nolabel="1" options="{'image_preview': 'image_128'}"/>
</group>
</group>
<field name="lang" invisible="True"/>
<field name="user_id" invisible="True"/>
<field name="image_128" invisible="1"/>
</sheet>
</form>
</field>
</page>
<page name="seller" string="Penjual">
<group>
<group>
......
from odoo import fields, models, api
import base64
import os
from odoo import fields, models, api, tools
ADDRESS_FIELDS = (
'street', 'street2', 'zip', 'city', 'state_id', 'country_id',
......@@ -8,21 +11,17 @@ ADDRESS_FIELDS = (
class ResPartner(models.Model):
_inherit = 'res.partner'
# company_id = fields.Many2one('res.company', string="Company",
# default=lambda self: self.env.company.id
# if not self.company_id else False
# )
#
# country_id = fields.Many2one('res.country', string="Country",
# default=lambda self: self.env.company.country_id
# if not self.country_id else False
# )
# state_id = fields.Many2one('res.country.state', string="State",
# default=lambda self: self.env.company.state_id
# if not self.state_id else False
# )
#
def _get_identity_card(self) -> bytes:
return base64.b64encode(open(os.path.join(
tools.config['root_path'], 'addons', 'base', 'static', 'img',
'avatar.png'), 'rb').read())
identity_number = fields.Char(string="Identity Number", size=16)
identity_card = fields.Binary(default=_get_identity_card, string="ID Card",
readonly=False)
district_id = fields.Many2one('res.district', string="Kabupaten/Kota",
ondelete='restrict', domain="[('state_id', '=?', state_id)]"
# default=lambda self: self.env.company.district_id
......
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<data>
<record id="action_partner_config_id" model="ir.actions.act_window">
<field name="name">Partner</field>
<field name="res_model">res.partner</field>
<field name="view_mode">kanban,tree,form</field>
<field name="help" type="html">
<p class="o_view_nocontent_smiling_face">
Partner
</p>
</field>
</record>
<record id="partner_form_id" model="ir.ui.view">
<field name="name">partner.form.id.inherit</field>
<field name="model">res.partner</field>
<field name="priority">9</field>
<field name="inherit_id" ref="base.view_partner_form"/>
<field name="arch" type="xml">
<xpath expr="//field[@name='type']" position="before">
<field name="identity_number"/>
</xpath>
<xpath expr="//field[@name='city']" position="attributes">
<attribute name="invisible">1</attribute>
</xpath>
<xpath expr="//field[@name='state_id']" position="before">
<field name="village_id" class="o_address_state" placeholder="Desa/Kel"
options="{'no_open': True, 'no_quick_create': True}"
attrs="{'readonly': [('type', '=', 'contact'),('parent_id', '!=', False)]}"
context="{'sub_district_id': sub_district_id, 'default_sub_district_id': sub_district_id,
'district_id': district_id}"
domain="[('sub_district_id', '=?', sub_district_id)]"/>
<field name="sub_district_id" class="o_address_state" placeholder="Kecamatan"
options="{'no_open': True, 'no_quick_create': True}"
attrs="{'readonly': [('type', '=', 'contact'),('parent_id', '!=', False)]}"
context="{'district_id': district_id, 'default_district_id': district_id,
'state_id':state_id}"
domain="[('district_id', '=?', district_id)]"/>
<field name="district_id" class="o_address_state" placeholder="Kab/Kota"
options="{'no_open': True, 'no_quick_create': True}"
attrs="{'readonly': [('type', '=', 'contact'),('parent_id', '!=', False)]}"
context="{'state_id': state_id, 'default_state_id': state_id}"
domain="[('state_id', '=?', state_id)]"/>
</xpath>
</field>
</record>
</data>
</odoo>
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<data>
<record id="action_partner_config_id" model="ir.actions.act_window">
<field name="name">Partner</field>
<field name="res_model">res.partner</field>
<field name="view_mode">kanban,tree,form</field>
<field name="help" type="html">
<p class="o_view_nocontent_smiling_face">
Partner
</p>
</field>
</record>
<record id="partner_form_id" model="ir.ui.view">
<field name="name">partner.form.id.inherit</field>
<field name="model">res.partner</field>
<field name="priority">9</field>
<field name="inherit_id" ref="base.view_partner_form"/>
<field name="arch" type="xml">
<xpath expr="//field[@name='type']" position="before">
<field name="identity_number"/>
</xpath>
<xpath expr="//field[@name='city']" position="attributes">
<attribute name="invisible">1</attribute>
</xpath>
<xpath expr="//field[@name='state_id']" position="before">
<field name="village_id" class="o_address_state" placeholder="Desa/Kel"
options="{'no_open': True, 'no_quick_create': True}"
attrs="{'readonly': [('type', '=', 'contact'),('parent_id', '!=', False)]}"
context="{'sub_district_id': sub_district_id, 'default_sub_district_id': sub_district_id,
'district_id': district_id}"
domain="[('sub_district_id', '=?', sub_district_id)]"/>
<field name="sub_district_id" class="o_address_state" placeholder="Kecamatan"
options="{'no_open': True, 'no_quick_create': True}"
attrs="{'readonly': [('type', '=', 'contact'),('parent_id', '!=', False)]}"
context="{'district_id': district_id, 'default_district_id': district_id,
'state_id':state_id}"
domain="[('district_id', '=?', district_id)]"/>
<field name="district_id" class="o_address_state" placeholder="Kab/Kota"
options="{'no_open': True, 'no_quick_create': True}"
attrs="{'readonly': [('type', '=', 'contact'),('parent_id', '!=', False)]}"
context="{'state_id': state_id, 'default_state_id': state_id}"
domain="[('state_id', '=?', state_id)]"/>
</xpath>
<xpath expr="//field[@name='category_id']" position="after">
<field name="identity_card" widget="image"
nolabel="0" options="{'image_preview': 'image_128'}"/>
</xpath>
<xpath expr="//field[@name='child_ids']//form//field[@name='city']" position="replace"/>
<xpath expr="//field[@name='child_ids']//form//field[@name='state_id']" position="before">
<field name="village_id" class="o_address_street" placeholder="Desa/Kel"
options="{'no_open': True, 'no_create': True}"
attrs="{'readonly': [('type', '=', 'contact'),('parent_id', '!=', False)]}"
context="{'sub_district_id': sub_district_id, 'default_sub_district_id': sub_district_id,
'district_id': district_id}"
domain="[('sub_district_id', '=?', sub_district_id)]"/>
<field name="sub_district_id" class="o_address_street" placeholder="Kecamatan"
options="{'no_open': True, 'no_create': True}"
attrs="{'readonly': [('type', '=', 'contact'),('parent_id', '!=', False)]}"
context="{'district_id': district_id, 'default_district_id': district_id,
'state_id':state_id}"
domain="[('district_id', '=?', district_id)]"/>
<field name="district_id" class="o_address_street" placeholder="Kab/Kota"
options="{'no_open': True, 'no_quick_create': True}"
attrs="{'readonly': [('type', '=', 'contact'),('parent_id', '!=', False)]}"
context="{'state_id': state_id, 'default_state_id': state_id}"
domain="[('state_id', '=?', state_id)]"/>
</xpath>
<xpath expr="//field[@name='child_ids']//form//field[@name='mobile']" position="after">
<field name="identity_card" widget="image"
nolabel="0" options="{'image_preview': 'image_128'}"/>
</xpath>
</field>
</record>
</data>
</odoo>
Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!