Commit a431c235 by aagusti

rencana tandur

1 parent 6c8d2143
Showing 229 changed files with 4532 additions and 5 deletions
......@@ -53,10 +53,10 @@ class IdgLetter(models.Model):
default=fields.Date.context_today
)
sender_id = fields.Many2one("res.partner")
contact_id = fields.Many2one('res.partner',
tracking=True,
required=True, )
typ = fields.Selection([('in', 'Surat Masuk'),
('out', 'Surat Keluar'),
], default='in')
......@@ -75,6 +75,12 @@ class IdgLetter(models.Model):
tracking=True,
string='Waktu Penyampaian') #penyampaian
# department_id = fields.Many2one('hr.department', string="Department", default=)
# def _compute_department_short(self):
# for rec in self:
# rec.department_short = rec.department_id.short_name
#
# department_short = fields.Char(compute="_compute_department_short", store=True)
type_id = fields.Many2one('idg.letter.type', required=True, string="Type")
......@@ -162,8 +168,8 @@ class IdgLetter(models.Model):
employee_rec = self.env['hr.employee'].search([('user_id', '=', self.env.uid)], limit=1)
return employee_rec.id
employee_id = fields.Many2one('hr.employee', string="Employee", default=_get_employee_id, readonly=True,
required=True)
employee_id = fields.Many2one('hr.employee', string="Employee", default=_get_employee_id,
required=True, read=['base.group_user'])
# by default store = False this means the value of this field
# is always computed.
......
......@@ -36,7 +36,7 @@
</field>
</record>
<record id="letter_incoming_form" model="ir.ui.view">
<record id="letter_form" model="ir.ui.view">
<field name="name">idg.letter.form</field>
<field name="model">idg.letter</field>
<field name="arch" type="xml">
......@@ -81,7 +81,6 @@
placeholder="Subject"/>
</h1>
</div>
<div colspan="12">
<h2>
......@@ -96,6 +95,9 @@
<!-- </h3>-->
</div>
<!-- <field name="department_id"-->
<!-- attrs="{'readonly':[('state','!=','draft')], 'invisible': [('typ','=','in')]}"/>-->
<field name="parent_id" string="Reply To"
attrs="{'readonly':[('state','!=','draft')], 'invisible': [('typ','=','in')]}"/>
......@@ -104,6 +106,10 @@
<field name="contact_id" string="To"
attrs="{'readonly':[('state','!=','draft')], 'invisible':[('typ','=','in')]}"/>
<field name="employee_id"
attrs="{'readonly':[('state','!=','draft')], 'invisible':[('typ','=','in')]}"
groups="idg_letter.group_idg_letter_user"/>
<field name="date" attrs="{'readonly':[('state','!=','draft')]}"/>
<field name="secrecy" required="1"/>
<field name="delivery_speed" attrs="{'invisible':[('typ','!=','out')]}"/>
......
E-Office Letter Management
-----
#Fungsi
1. Mengelola surat masuk/surat keluar
2. Mengelola Penomoran Surat
#User Type
1. Generic User
2. Letter User
3. Letter Administrator
#Status Surat
1. Draft
2. Pending (Waiting for Approval)
3. Approved (Di approve semua user required)
4. Refused (Dikembalikan kepada pembuat)
* Salah satu required approval melakukan refuse/penolakan
* Bisa diubah jadi draft oleh pembuat
5. Canceled
* Salah satu required approval melakukan cancel data
# Surat Masuk
1. "Letter User" Membuat surat masuk
2. Sistem melakukan auto routing ke Top Manager
3. Setiap Manager dapat menambahkan routing ke staff di bawahnya
# Surat Keluar
1. Setiap User berhak membuat surat keluar
2. System melakukan otomasi routing ke manager user
3. Manager melakukan proses autorisasi
4. "No Surat" diinput oleh "Letter User" jika semua manager yang wajib sudah approved
# Restriction
1. Generic user
1. Hanya bisa membaca data milik sendiri
2. Melakukan approval untuk surat yang diterima
3. Menambahkan pegawai untuk approval
4. Tidak bisa menghapus surat yang sudah dibuat
5. Tidak bisa menghapus Approval default (required)
6. Tidak bisa mengisi code surat keluar
2. Letter User
1. Input Data Code Surat Keluar
3. Letter Administrator
1. Membaca semua record surat
2. Menghapus record yang belum approval
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from . import controllers
from . import models
from . import wizard
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
{
'name': 'PUBLIC TRANSPORT',
'version': '0.1',
'summary': 'Public Transfor Management',
'sequence': 11,
'description': """
PUBLIC TRANSPORT MANAGEMENT
""",
'category': 'IDG MANAGEMENT',
'website': 'https://opensipkd.com',
'images': [],
'depends': ['base_geoengine', 'id_gov'],
'data': [
'security/account_security.xml',
'security/ir.model.access.csv',
# 'security/ir_rule.xml',
# 'data/sequence.xml',
# 'data/category.xml',
# 'data/type.xml',
'views/idg_trayek_vehicle.xml',
'views/idg_vehicle.xml',
'views/idg_road.xml',
'views/idg_trayek.xml',
'views/partner.xml',
'views/menus.xml',
# 'views/idg_letter_category.xml',
# 'views/idg_letter_type.xml',
# 'views/idg_letter.xml',
# 'views/task_letter.xml',
],
'demo': [
# 'security/ir_rule.xml',
# 'data/res_user.xml',
],
'qweb': [],
'installable': True,
'application': True,
'auto_install': False,
'license': 'LGPL-3',
'module': 'idg_trayek'
}
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from . import onboarding
from . import portal
from odoo import http
from odoo.http import request
class OnboardingController(http.Controller):
@http.route('/pad/pad_invoice_onboarding', auth='user', type='json')
def pad_invoice_onboarding(self):
""" Returns the `banner` for the pad invoice onboarding panel.
It can be empty if the user has closed it or if he doesn't have
the permission to see it. """
company = request.env.company
if not request.env.is_admin() or \
company.pad_invoice_onboarding_state == 'closed':
return {}
return {
'html': request.env.ref('pad.pad_invoice_onboarding_panel')._render({
'company': company,
'state': company.get_and_update_pad_invoice_onboarding_state()
})
}
@http.route('/pad/pad_dashboard_onboarding', auth='user', type='json')
def pad_dashboard_onboarding(self):
""" Returns the `banner` for the pad dashboard onboarding panel.
It can be empty if the user has closed it or if he doesn't have
the permission to see it. """
company = request.env.company
if not request.env.is_admin() or \
company.pad_dashboard_onboarding_state == 'closed':
return {}
return {
'html': request.env.ref('pad.pad_dashboard_onboarding_panel')._render({
'company': company,
'state': company.get_and_update_pad_dashboard_onboarding_state()
})
}
# -*- 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.exceptions import AccessError, MissingError
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 CustomerPortal(CustomerPortal):
def _prepare_home_portal_values(self, counters):
values = super()._prepare_home_portal_values(counters)
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
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))
values = {
'sales': sales,
'resize_to_48': resize_to_48,
}
return self._get_page_view_values(sales, access_token, values,
'my_bphtbs_history', False, **kwargs)
@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()
BphtbSales = request.env['bphtb.sales']
domain = []
if date_begin and date_end:
domain += [('create_date', '>', date_begin), ('create_date', '<=', date_end)]
searchbar_sortings = {
'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 value
if not sortby:
sortby = 'date'
order = searchbar_sortings[sortby]['order']
searchbar_filters = {
'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']
# count for pager
bphtb_count = BphtbSales.search_count(domain)
# make pager
pager = portal_pager(
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
)
# 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,
'saless': saless,
'page_name': 'bphtb',
'pager': pager,
'searchbar_sortings': searchbar_sortings,
'sortby': sortby,
'searchbar_filters': OrderedDict(sorted(searchbar_filters.items())),
'filterby': filterby,
'default_url': '/my/bphtb',
})
return request.render("idg_bphtb.portal_my_bphtb_saless", values)
@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:
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=order_sudo, report_type=report_type,
report_ref='idg_bphtb.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("idg_bphtb.portal_my_bphtb_sales_update_date", values)
return request.render("idg_bphtb.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)
id,code,name,min_omzet,rate,disc,company_id:id,under_value
bphtb_01,01,Jual Beli,60000000,5,0,base.main_company,False
bphtb_02,02,Tukar Menukar,60000000,5,0,base.main_company,False
bphtb_03,03,Hibah,60000000,5,0,base.main_company,False
bphtb_04,04,Hibah Wasiat,300000000,5,50,base.main_company,False
bphtb_05,05,Waris,300000000,5,50,base.main_company,False
bphtb_06,06,Pemasukan dalam Perseroan atau Badan Hukum Lainnya,60000000,5,0,base.main_company,False
bphtb_07,07,Pemisahan Hak yang mengakibatkan Peralihan,60000000,5,0,base.main_company,False
bphtb_08,08,Penunjukan Pembelli dalam Lelang,60000000,5,0,base.main_company,True
bphtb_09,09,Pelaksanaan Putusan Hakim yang mempunyai kekuatan hukum tetap,60000000,5,0,base.main_company,True
bphtb_10,10,Penggabungan Usaha,60000000,5,0,base.main_company,False
bphtb_11,11,Peleburan Usaha,60000000,5,0,base.main_company,False
bphtb_12,12,Pemekaran Usaha,60000000,5,0,base.main_company,False
bphtb_13,13,Hadiah,60000000,5,0,base.main_company,False
bphtb_14,14,Perolehan hak Rumah Sederhana Sehat dan RSS melalui KPR bersubsidi,60000000,5,0,base.main_company,False
bphtb_15,15,Pemberian Hak Baru Kelanjutan Pelepasan Hak,60000000,5,0,base.main_company,False
bphtb_16,16,Pemberian hak baru diluar pelepasan hak,60000000,5,0,base.main_company,False
bphtb_17,17,Tax Amnesti,60000000,5,0,base.main_company,False
bphtb_18,18,Peningkatan Status,0,0,0,base.main_company,False
<?xml version="1.0"?>
<odoo>
<data noupdate="1">
<record id="idg_letter_cat_800" model="idg.letter.category">
<field name='code'>idg_letter_cat_800</field>
<field name='name'>Kepegawaian</field>
<field name="prefix">800/</field>
<field name="suffix">/%(month)s/%(year)s</field>
<field name="padding">4</field>
</record>
<record id="idg_letter_cat_900" model="idg.letter.category">
<field name='code'>idg_letter_cat_900</field>
<field name='name'>KEUANGAN</field>
<field name="prefix">900/</field>
<field name="suffix">/%(month)s/%(year)s</field>
<field name="padding">4</field>
</record>
<record id="idg_letter_cat_920" model="idg.letter.category">
<field name='code'>idg_letter_cat_920</field>
<field name='name'>OTORISASI / SKO</field>
<field name="prefix">920/</field>
<field name="suffix">/%(month)s/%(year)s</field>
<field name="padding">4</field>
</record>
<record id="idg_letter_cat_930" model="idg.letter.category">
<field name='code'>idg_letter_cat_930</field>
<field name='name'>VERIFIKASI</field>
<field name="prefix">930/</field>
<field name="suffix">/%(month)s/%(year)s</field>
<field name="padding">4</field>
</record>
<record id="idg_letter_cat_940" model="idg.letter.category">
<field name='code'>idg_letter_cat_940</field>
<field name='name'>PEMBUKUAN</field>
<field name="prefix">940/</field>
<field name="suffix">/%(month)s/%(year)s</field>
<field name="padding">4</field>
</record>
<record id="idg_letter_cat_950" model="idg.letter.category">
<field name='code'>idg_letter_cat_950</field>
<field name='name'>PERBENDAHARAAN</field>
<field name="prefix">950/</field>
<field name="suffix">/%(month)s/%(year)s</field>
<field name="padding">4</field>
</record>
<record id="idg_letter_cat_960" model="idg.letter.category">
<field name='code'>idg_letter_cat_960</field>
<field name='name'>PEMBINAAN KEBENDAHARAAN</field>
<field name="prefix">960/</field>
<field name="suffix">/%(month)s/%(year)s</field>
<field name="padding">4</field>
</record>
<record id="idg_letter_cat_961" model="idg.letter.category">
<field name='code'>idg_letter_cat_961</field>
<field name='name'>Pemeriksaan Kas Dan Hasil Pemeriksaan Kas</field>
<field name="prefix">961/</field>
<field name="suffix">/%(month)s/%(year)s</field>
<field name="padding">4</field>
</record>
<record id="idg_letter_cat_970" model="idg.letter.category">
<field name='code'>idg_letter_cat_970</field>
<field name='name'>PENDAPATAN</field>
<field name="prefix">940/</field>
<field name="suffix">/%(month)s/%(year)s</field>
<field name="padding">4</field>
</record>
<record id="idg_letter_cat_990" model="idg.letter.category">
<field name='code'>idg_letter_cat_990</field>
<field name='name'>BENDAHARAWAN</field>
<field name="prefix">990/</field>
<field name="suffix">/%(month)s/%(year)s</field>
<field name="padding">4</field>
</record>
</data>
</odoo>
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<data noupdate="1">
<record id="bphtb_partner_admin_kab_id" model="res.partner">
<field name="name">Admin BPHTB Kab/Kota</field>
<field name="street">Jalan-jalan</field>
<field name="country_id" ref="base.id"/>
<field name="state_id" ref="base.state_id_jb"/>
<field name="district_id" ref="id_gov.ct_jb_71"/>
<field name="company_id" ref="base.main_company"/>
<field name="zip">90241</field>
<field name="phone">+62 812-345-678</field>
<field name="email">info@company.idexample.com</field>
<field name="website">www.idexample.com</field>
</record>
<record id="bphtb_user_admin_kab_id" model="res.users">
<field name="login">bphtb_admin</field>
<field name="password">admin</field>
<field name="partner_id" ref="bphtb_partner_admin_kab_id"/>
<field name="company_id" ref="base.main_company"/>
<field name="company_ids" eval="[(4,ref('base.main_company'))]"/>
<field name="groups_id"
eval="[(6,0,[ref('base.group_user'), ref('idg_bphtb.group_bphtb_admin')])]"/>
</record>
<record id="bphtb_partner_ppat_kab_id" model="res.partner">
<field name="name">PPAT Kab/Kota</field>
<field name="street">Jalan-jalan</field>
<field name="country_id" ref="base.id"/>
<field name="state_id" ref="base.state_id_jb"/>
<field name="district_id" ref="id_gov.ct_jb_71"/>
<field name="company_id" ref="base.main_company"/>
<field name="zip">90241</field>
<field name="type">ppat</field>
<field name="phone">+62 812-345-678</field>
<field name="email">info@company.idexample.com</field>
<field name="website">www.idexample.com</field>
</record>
<record id="bphtb_user_ppat_kab_id" model="res.users">
<field name="login">ppat</field>
<field name="password">ppat</field>
<field name="partner_id" ref="bphtb_partner_ppat_kab_id"/>
<field name="company_id" ref="base.main_company"/>
<field name="company_ids" eval="[(4,ref('base.main_company'))]"/>
<field name="groups_id"
eval="[(6,0,[ref('base.group_user'), ref('idg_bphtb.group_bphtb_ppat')])]"/>
</record>
<record id="bphtb_partner_wp_kab_id" model="res.partner">
<field name="name">Wajib Pajak BPHTB</field>
<field name="street">Jalan-jalan</field>
<field name="country_id" ref="base.id"/>
<field name="state_id" ref="base.state_id_jb"/>
<field name="district_id" ref="id_gov.ct_jb_71"/>
<field name="company_id" ref="base.main_company"/>
<field name="zip">90241</field>
<field name="type">wp</field>
<field name="phone">+62 812-345-678</field>
<field name="email">info@company.idexample.com</field>
<field name="website">www.idexample.com</field>
</record>
<record id="bphtb_partner_penjual_kab_id" model="res.partner">
<field name="name">Wajib Pajak Penjual BPHTB</field>
<field name="street">Jalan-jalan</field>
<field name="country_id" ref="base.id"/>
<field name="state_id" ref="base.state_id_jb"/>
<field name="district_id" ref="id_gov.ct_jb_71"/>
<field name="company_id" ref="base.main_company"/>
<field name="zip">90241</field>
<field name="type">wp</field>
<field name="phone">+62 812-345-678</field>
<field name="email">info@company.idexample.com</field>
<field name="website">www.idexample.com</field>
</record>
</data>
</odoo>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<!-- © 2022 Agus Gustiana <aa.gustiana@gmail.com>
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). -->
<odoo>
<data noupdate="1">
<!-- Sequences for Incoming Letter -->
<record id="seq_in_idg_letter" model="ir.sequence">
<field name="name">IDG Incoming Letter</field>
<field name="code">in.idg.letter</field>
<field name="prefix">IN/%(year)s/%(month)s/%(day)s/</field>
<field name="padding">3</field>
</record>
<!-- Sequences for Outgoing Letter -->
<record id="seq_out_idg_letter" model="ir.sequence">
<field name="name">IDG Outgoing Letter</field>
<field name="code">out.idg.letter</field>
<field name="prefix">OUT/%(year)s/%(month)s/%(day)s/</field>
<field name="padding">3</field>
</record>
</data>
</odoo>
<?xml version="1.0"?>
<odoo>
<data noupdate="0">
<record id="idg_letter_01" model="idg.letter.type">
<field name='code'>01</field>
<field name='name'>Peraturan</field>
<field name='active'>1</field>
</record>
<record id="idg_letter_02" model="idg.letter.type">
<field name='code'>02</field>
<field name='name'>Pedoman</field>
<field name='active'>1</field>
</record>
<record id="idg_letter_03" model="idg.letter.type">
<field name='code'>03</field>
<field name='name'>Petunjuk Pelaksanaan</field>
<field name='active'>1</field>
</record>
<record id="idg_letter_04" model="idg.letter.type">
<field name='code'>04</field>
<field name='name'>Standar Operasional dan Prosedur</field>
<field name='active'>1</field>
</record>
<record id="idg_letter_05" model="idg.letter.type">
<field name='code'>05</field>
<field name='name'>Keputusan</field>
<field name='active'>1</field>
</record>
<record id="idg_letter_06" model="idg.letter.type">
<field name='code'>06</field>
<field name='name'>Instruksi</field>
<field name='active'>1</field>
</record>
<record id="idg_letter_07" model="idg.letter.type">
<field name='code'>07</field>
<field name='name'>Surat Perintah</field>
<field name='active'>1</field>
</record>
<record id="idg_letter_08" model="idg.letter.type">
<field name='code'>08</field>
<field name='name'>Surat Tugas</field>
<field name='active'>1</field>
</record>
<record id="idg_letter_09" model="idg.letter.type">
<field name='code'>09</field>
<field name='name'>Nota Dinas</field>
<field name='active'>1</field>
</record>
<record id="idg_letter_10" model="idg.letter.type">
<field name='code'>10</field>
<field name='name'>Memorandum</field>
<field name='active'>1</field>
</record>
<record id="idg_letter_11" model="idg.letter.type">
<field name='code'>11</field>
<field name='name'>Surat Dinas</field>
<field name='active'>1</field>
</record>
<record id="idg_letter_12" model="idg.letter.type">
<field name='code'>12</field>
<field name='name'>Surat Undangan</field>
<field name='active'>1</field>
</record>
<record id="idg_letter_13" model="idg.letter.type">
<field name='code'>13</field>
<field name='name'>Surat Perjanjian</field>
<field name='active'>1</field>
</record>
<record id="idg_letter_14" model="idg.letter.type">
<field name='code'>14</field>
<field name='name'>Surat Kuasa</field>
<field name='active'>1</field>
</record>
<record id="idg_letter_15" model="idg.letter.type">
<field name='code'>15</field>
<field name='name'>Berita Acara</field>
<field name='active'>1</field>
</record>
<record id="idg_letter_16" model="idg.letter.type">
<field name='code'>16</field>
<field name='name'>Surat Keterangan</field>
<field name='active'>1</field>
</record>
<record id="idg_letter_17" model="idg.letter.type">
<field name='code'>17</field>
<field name='name'>Surat Pengantar</field>
<field name='active'>1</field>
</record>
<record id="idg_letter_18" model="idg.letter.type">
<field name='code'>18</field>
<field name='name'>Pengumuman</field>
<field name='active'>1</field>
</record>
<record id="idg_letter_19" model="idg.letter.type">
<field name='code'>19</field>
<field name='name'>Laporan</field>
<field name='active'>1</field>
</record>
<record id="idg_letter_20" model="idg.letter.type">
<field name='code'>20</field>
<field name='name'>Telaahan Staff</field>
<field name='active'>1</field>
</record>
</data>
</odoo>
id,ppat_id:id,wp_id:id,seller_id:id,state,nop,tax_year,luas_bumi,luas_bng,njop_bumi,njop_bng,luas_bumi_bersama,luas_bng_bersama,njop_bumi_bersama,njop_bng_bersama,jenis_id:id,rate,min_omzet,disc_sk,npop,basic,fine,amount,disc_amount,owed,typ,company_id:id,certicate_no
sspd_01,bphtb_partner_ppat_kab_id,bphtb_partner_wp_kab_id,bphtb_partner_penjual_kab_id,draft,367601000100100010,2021,100,50,500000000,250000000,0,0,00,0,bphtb_01,5,60000000,,1000000000,0,0,0,0,0,sspd,base.main_company,-
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<data noupdate="1">
<record id="pdl_partner_company_id" model="res.partner">
<field name="name">Kabupaten/Kota</field>
<field name="street">Jalan-jalan</field>
<field name="country_id" ref="base.id"/>
<field name="state_id" ref="base.state_id_jb"/>
<field name="district_id" ref="id_gov.ct_jb_71"/>
<field name="zip">90241</field>
<field name="phone">+62 812-345-678</field>
<field name="email">info@company.idexample.com</field>
<field name="website">www.idexample.com</field>
</record>
<record id="pdl_company_id" model="res.company">
<field name="name">Kabupaten/Kota Company</field>
<field name="partner_id" ref="pdl_partner_company_id"/>
</record>
</data>
<data>
<function model="res.users" name="write">
<value eval="[ref('base.user_root'), ref('base.user_admin'), ref('base.user_demo')]"/>
<value eval="{'company_ids': [(4, ref('pdl_kab.pdl_company_id'))]}"/>
</function>
</data>
</odoo>
\ No newline at end of file
from . import idg_road
from . import idg_trayek
import logging
from datetime import datetime, timedelta
import pytz
from odoo import models, api, fields, _
# from odoo.addons.base.models.ir_sequence import (_create_sequence, _drop_sequences, _alter_sequence, _select_nextval,
# _update_nogap)
# from odoo.tools import sql
from odoo.exceptions import UserError
from psycopg2 import sql
_logger = logging.getLogger(__name__)
class IdgRoad(models.Model):
_name = 'idg.road'
_description = 'Public Road Management'
_order = "name"
name = fields.Char(required=True)
code = fields.Char(string='Code')
length = fields.Float(string='Length')
active = fields.Boolean(default=True, string="Active")
geom = fields.GeoLine(srid=4326)
from datetime import datetime, timedelta
from odoo import api, fields, models, _
import logging
import re
_logger = logging.getLogger(__name__)
class IdgTrayek(models.Model):
_name = 'idg.trayek.route'
_description = 'Public Route'
# _inherit = ['mail.thread', 'mail.activity.mixin']
# _sequence_field = "code"
# _sequence_date_field = "date"
code = fields.Char(index=True, string='Code')
name = fields.Char(index=True, string='Name', size=255, required=True)
active = fields.Boolean(default=True, string='Active')
# geom = field.Geom()
trayek_line = fields.One2many('idg.trayek.route.line', 'trayek_id',
string='Trayek Lines',
copy=True, auto_join=True)
geom = fields.GeoLine(srid=4326)
class IdgTrayekLine(models.Model):
_name = 'idg.trayek.route.line'
_description = 'Public Route Line'
# _inherit = ['mail.thread', 'mail.activity.mixin', ]
trayek_id = fields.Many2one('idg.trayek.route')
road_id = fields.Many2one('idg.road')
class IdgVehicle(models.Model):
_name = 'idg.vehicle'
_description = 'Vehicle Merek'
# _inherit = ['mail.thread', 'mail.activity.mixin']
# _sequence_field = "code"
# _sequence_date_field = "date"
# code = fields.Char(index=True, string='Code')
name = fields.Char(index=True, string='Name', size=255, required=True)
class IdgTrayekVehicle(models.Model):
_name = 'idg.trayek.vehicle'
_description = 'Public Transport Route'
# _inherit = ['mail.thread', 'mail.activity.mixin', ]
code = fields.Char(index=True, string='Code', compute='_compute_code',
store=True, copy=False, tracking=True)
name = fields.Char(string='Name', index=True)
partner_id = fields.Many2one('res.partner')
vehicle_id = fields.Many2one('idg.vehicle')
route_id = fields.Many2one('idg.trayek.route')
permit_no = fields.Char(index=True, string='Permit')
permit_due = fields.Date(string='Due Date')
production_year = fields.Char(size=4, string='Production Year')
active = fields.Boolean(default=True, string='Active')
@api.depends('name')
def _compute_code(self):
for rec in self:
rec_str = re.sub('[0-9]', " ", rec.name).split()
if len(rec_str) == 1:
rec_str.append(" ")
rec_num = re.sub("[a-zA-Z]", " ", rec.name)
rec.code = f"{rec_str[0].ljust(2)}{rec_str[1].ljust(3)}{rec_num.strip()}"
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<data noupdate="0">
<record model="ir.module.category" id="idg_trayek">
<field name="name">Trayek Management</field>
<field name="description">Trayek Management</field>
<field name="sequence">12</field>
</record>
<record id="group_idg_trayek_user" model="res.groups">
<field name="name">User</field>
<field name="category_id" ref="idg_trayek"/>
</record>
<record id="group_idg_trayek_admin" model="res.groups">
<field name="name">Administrator</field>
<field name="category_id" ref="idg_trayek"/>
<field name="implied_ids" eval="[(4, ref('group_idg_trayek_user'))]"/>
<field name="users" eval="[(4, ref('base.user_root')), (4, ref('base.user_admin'))]"/>
</record>
</data>
</odoo>
"id","name","model_id:id","group_id:id","perm_read","perm_write","perm_create","perm_unlink"
"access_idg_letter_category_user","access.idg.letter.category.user","model_idg_letter_category","base.group_user",1,0,0,0
"access_idg_letter_user","access.idg.letter.user","model_idg_letter","base.group_user",1,1,1,1
"access_idg_letter_routes_user","access.idg.letter.routes.user","model_idg_letter_routes","base.group_user",1,0,1,0
"access_idg_letter_comments_user","access.idg.letter.comments.user","model_idg_letter_routes","base.group_user",1,0,1,0
"access_idg_letter_docs_user","access.idg.letter.docs.user","model_idg_letter_comments","base.group_user",1,0,1,0
"access_idg_letter_comments_admin","access.idg.letter.comments.admin","model_idg_letter_comments","group_idg_letter_admin",1,1,1,1
"access_idg_letter_docs_admin","access.idg.letter.docs.admin","model_idg_letter_docs","group_idg_letter_admin",1,1,1,1
"access_idg_letter_category_admin","access.idg.letter.category.admin","model_idg_letter_category","group_idg_letter_admin",1,1,1,1
"access_idg_letter_category_user","access.idg.letter.category.user","model_idg_letter_category","group_idg_letter_user",1,1,1,1
"access_idg_letter_category_base","access.idg.letter.category.base","model_idg_letter_category","base.group_user",1,0,0,0
"access_idg_letter_category_approver_base","access.idg.letter.category.approver.base","model_idg_letter_category_approver","base.group_user",1,0,0,0
"access_idg_letter_category_approver_admin","access.idg.letter.category.approver.admin","model_idg_letter_category_approver","group_idg_letter_admin",1,1,1,1
"access_idg_letter_admin","access.idg.letter.admin","model_idg_letter","group_idg_letter_admin",1,1,1,1
"access_idg_letter_approver_admin","access.idg.letter.approver.admin","model_idg_letter_approver","group_idg_letter_admin",1,1,1,1
\ No newline at end of file
"id","name","model_id:id","group_id:id","perm_read","perm_write","perm_create","perm_unlink"
"access_idg_road","access.idg.road","model_idg_road","base.group_user",1,0,0,0
"access_idg_road_user","access.idg.road.user","model_idg_road","group_idg_trayek_user",1,1,1,0
"access_idg_road_admin","access.idg.road.admin","model_idg_road","group_idg_trayek_admin",1,1,1,1
"access_idg_trayek_route","access.idg.trayek.route","model_idg_trayek_route","base.group_user",1,0,0,0
"access_idg_trayek_route_user","access.idg.trayek.route.user","model_idg_trayek_route","group_idg_trayek_user",1,1,1,0
"access_idg_trayek_route_admin","access.idg.trayek.route.admin","model_idg_trayek_route","group_idg_trayek_admin",1,1,1,1
"access_idg_trayek_route_line","access.idg.trayek.route.line","model_idg_trayek_route_line","base.group_user",1,0,0,0
"access_idg_trayek_route_line_user","access.idg.trayek.route.line.user","model_idg_trayek_route_line","group_idg_trayek_user",1,1,1,0
"access_idg_trayek_route_line_admin","access.idg.trayek.route.line.admin","model_idg_trayek_route_line","group_idg_trayek_admin",1,1,1,1
"access_idg_vehicle","access.idg.vehicle","model_idg_vehicle","base.group_user",1,0,0,0
"access_idg_vehicle_user","access.idg.vehicle.user","model_idg_vehicle","group_idg_trayek_user",1,1,1,0
"access_idg_vehicle_admin","access.idg.vehicle.admin","model_idg_vehicle","group_idg_trayek_admin",1,1,1,1
"access_idg_trayek_vehicle","access.idg.trayek.vehicle","model_idg_trayek_vehicle","base.group_user",1,0,0,0
"access_idg_trayek_vehicle_user","access.idg.trayek.vehicle.user","model_idg_trayek_vehicle","group_idg_trayek_user",1,1,1,0
"access_idg_trayek_vehicle_admin","access.idg.trayek.vehicle.admin","model_idg_trayek_vehicle","group_idg_trayek_admin",1,1,1,1
<?xml version="1.0"?>
<odoo>
<data noupdate="0">
<record model="ir.rule" id="idg_letter_owner_rule">
<field name="name">IDG Letter Owner Rule</field>
<field name="model_id" ref="model_idg_letter"/>
<field name="groups" eval="[4,ref('base.group_user')]"/>
<field name="domain_force">[('create_uid', '=', user.id)]</field>
<field name="perm_read" eval="True"/>
<field name="perm_create" eval="True"/>
<field name="perm_write" eval="True"/>
<field name="perm_unlink" eval="False"/>
</record>
<record model="ir.rule" id="idg_letter_owner_delete_rule">
<field name="name">IDG Letter Owner Delete Rule</field>
<field name="model_id" ref="model_idg_letter"/>
<field name="groups" eval="[4,ref('base.group_user')]"/>
<field name="domain_force">[('create_uid', '=', user.id), ('state','=','canceled')]</field>
<field name="perm_read" eval="False"/>
<field name="perm_create" eval="False"/>
<field name="perm_write" eval="False"/>
<field name="perm_unlink" eval="True"/>
</record>
<record model="ir.rule" id="idg_letter_write_rule">
<field name="name">IDG Letter Write Rule</field>
<field name="model_id" ref="model_idg_letter"/>
<field name="groups" eval="[4,ref('base.group_user')]"/>
<!-- <field name="domain_force">[('approvers.create_uid', '=', user.id), ('state','in',['draft','new'])]</field>-->
<field name="perm_read" eval="False"/>
<field name="perm_create" eval="False"/>
<field name="perm_write" eval="True"/>
<field name="perm_unlink" eval="False"/>
</record>
<record model="ir.rule" id="idg_letter_approver_read_rule">
<field name="name">IDG Letter Approver Rule</field>
<field name="model_id" ref="model_idg_letter"/>
<field name="groups" eval="[4,ref('base.group_user')]"/>
<field name="domain_force">[('approver_ids.user_id.id', '=', user.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="idg_letter_approver_write_rule">
<field name="name">IDG Letter Approver Write Rule</field>
<field name="model_id" ref="model_idg_letter_approver"/>
<field name="groups" eval="[4,ref('base.group_user')]"/>
<field name="domain_force">[('required', '=', True)]</field>
<field name="perm_read" eval="True"/>
<field name="perm_create" eval="True"/>
<field name="perm_write" eval="True"/>
<field name="perm_unlink" eval="False"/>
</record>
<record model="ir.rule" id="idg_letter_approver_delete_rule">
<field name="name">IDG Letter Approver Delete Rule</field>
<field name="model_id" ref="model_idg_letter_approver"/>
<field name="groups" eval="[4,ref('base.group_user')]"/>
<field name="domain_force">[('required', '=', False)]</field>
<field name="perm_read" eval="True"/>
<field name="perm_create" eval="True"/>
<field name="perm_write" eval="True"/>
<field name="perm_unlink" eval="True"/>
</record>
<record model="ir.rule" id="idg_letter_admin_rule">
<field name="name">IDG Letter Admin Rule</field>
<field name="model_id" ref="model_idg_letter"/>
<field name="groups" eval="[4,ref('group_idg_letter_admin')]"/>
<field name="perm_read" eval="True"/>
<field name="perm_create" eval="True"/>
<field name="perm_write" eval="True"/>
<field name="perm_unlink" eval="True"/>
</record>
<record model="ir.rule" id="idg_letter_category_admin_rule">
<field name="name">IDG Letter Category Admin Rule</field>
<field name="model_id" ref="model_idg_letter_category"/>
<field name="groups" eval="[4,ref('group_idg_letter_admin')]"/>
<field name="perm_read" eval="True"/>
<field name="perm_create" eval="True"/>
<field name="perm_write" eval="True"/>
<field name="perm_unlink" eval="True"/>
</record>
<record model="ir.rule" id="idg_letter_category_user_rule">
<field name="name">IDG Letter Category User Rule</field>
<field name="model_id" ref="model_idg_letter_category"/>
<field name="groups" eval="[4,ref('group_idg_letter_user')]"/>
<field name="perm_read" eval="True"/>
<field name="perm_create" eval="True"/>
<field name="perm_write" eval="True"/>
<field name="perm_unlink" eval="False"/>
</record>
<record model="ir.rule" id="idg_letter_category_rule">
<field name="name">IDG Letter Category Rule</field>
<field name="model_id" ref="model_idg_letter_category"/>
<field name="groups" eval="[4,ref('base.group_user')]"/>
<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="idg_letter_category_approver_admin_rule">
<field name="name">IDG Letter Category Approver Admin Rule</field>
<field name="model_id" ref="model_idg_letter_category_approver"/>
<field name="groups" eval="[4,ref('group_idg_letter_admin')]"/>
<field name="perm_read" eval="True"/>
<field name="perm_create" eval="True"/>
<field name="perm_write" eval="True"/>
<field name="perm_unlink" eval="True"/>
</record>
<record model="ir.rule" id="idg_letter_category_approver_user_rule">
<field name="name">IDG Letter Category Approver User Rule</field>
<field name="model_id" ref="model_idg_letter_category_approver"/>
<field name="groups" eval="[4,ref('group_idg_letter_user')]"/>
<field name="perm_read" eval="True"/>
<field name="perm_create" eval="True"/>
<field name="perm_write" eval="True"/>
<field name="perm_unlink" eval="False"/>
</record>
<record model="ir.rule" id="idg_letter_category_approver_rule">
<field name="name">IDG Letter Category Approves Rule</field>
<field name="model_id" ref="model_idg_letter_category_approver"/>
<field name="groups" eval="[4,ref('base.group_user')]"/>
<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>
</data>
</odoo>
\ No newline at end of file
odoo.define('account.payment', function (require) {
"use strict";
var AbstractField = require('web.AbstractField');
var core = require('web.core');
var field_registry = require('web.field_registry');
var field_utils = require('web.field_utils');
var QWeb = core.qweb;
var _t = core._t;
var ShowPaymentLineWidget = AbstractField.extend({
events: _.extend({
'click .outstanding_credit_assign': '_onOutstandingCreditAssign',
}, AbstractField.prototype.events),
supportedFieldTypes: ['char'],
//--------------------------------------------------------------------------
// Public
//--------------------------------------------------------------------------
/**
* @override
* @returns {boolean}
*/
isSet: function () {
return true;
},
//--------------------------------------------------------------------------
// Private
//--------------------------------------------------------------------------
/**
* @private
* @override
*/
_render: function () {
var self = this;
var info = JSON.parse(this.value);
if (!info) {
this.$el.html('');
return;
}
_.each(info.content, function (k, v) {
k.index = v;
k.amount = field_utils.format.float(k.amount, {digits: k.digits});
if (k.date) {
k.date = field_utils.format.date(field_utils.parse.date(k.date, {}, {isUTC: true}));
}
});
this.$el.html(QWeb.render('ShowPaymentInfo', {
lines: info.content,
outstanding: info.outstanding,
title: info.title
}));
_.each(this.$('.js_payment_info'), function (k, v) {
var isRTL = _t.database.parameters.direction === "rtl";
var content = info.content[v];
var options = {
content: function () {
var $content = $(QWeb.render('PaymentPopOver', content));
var unreconcile_button = $content.filter('.js_unreconcile_payment').on('click', self._onRemoveMoveReconcile.bind(self));
$content.filter('.js_open_payment').on('click', self._onOpenPayment.bind(self));
return $content;
},
html: true,
placement: isRTL ? 'bottom' : 'left',
title: 'Payment Information',
trigger: 'focus',
delay: {"show": 0, "hide": 100},
container: $(k).parent(), // FIXME Ugly, should use the default body container but system & tests to adapt to properly destroy the popover
};
$(k).popover(options);
});
},
//--------------------------------------------------------------------------
// Handlers
//--------------------------------------------------------------------------
/**
* @private
* @override
* @param {MouseEvent} event
*/
_onOpenPayment: function (event) {
var paymentId = parseInt($(event.target).attr('payment-id'));
var moveId = parseInt($(event.target).attr('move-id'));
var res_model;
var id;
if (paymentId !== undefined && !isNaN(paymentId)) {
res_model = "account.payment";
id = paymentId;
} else if (moveId !== undefined && !isNaN(moveId)) {
res_model = "account.move";
id = moveId;
}
//Open form view of account.move with id = move_id
if (res_model && id) {
this.do_action({
type: 'ir.actions.act_window',
res_model: res_model,
res_id: id,
views: [[false, 'form']],
target: 'current'
});
}
},
/**
* @private
* @override
* @param {MouseEvent} event
*/
_onOutstandingCreditAssign: function (event) {
event.stopPropagation();
event.preventDefault();
var self = this;
var id = $(event.target).data('id') || false;
this._rpc({
model: 'account.move',
method: 'js_assign_outstanding_line',
args: [JSON.parse(this.value).move_id, id],
}).then(function () {
self.trigger_up('reload');
});
},
/**
* @private
* @override
* @param {MouseEvent} event
*/
_onRemoveMoveReconcile: function (event) {
var self = this;
var moveId = parseInt($(event.target).attr('move-id'));
var partialId = parseInt($(event.target).attr('partial-id'));
if (partialId !== undefined && !isNaN(partialId)) {
this._rpc({
model: 'account.move',
method: 'js_remove_outstanding_partial',
args: [moveId, partialId],
}).then(function () {
self.trigger_up('reload');
});
}
},
});
field_registry.add('payment', ShowPaymentLineWidget);
return {
ShowPaymentLineWidget: ShowPaymentLineWidget
};
});
odoo.define('account.AccountPortalSidebar', function (require) {
'use strict';
const dom = require('web.dom');
var publicWidget = require('web.public.widget');
var PortalSidebar = require('portal.PortalSidebar');
var utils = require('web.utils');
publicWidget.registry.AccountPortalSidebar = PortalSidebar.extend({
selector: '.o_portal_invoice_sidebar',
events: {
'click .o_portal_invoice_print': '_onPrintInvoice',
},
/**
* @override
*/
start: function () {
var def = this._super.apply(this, arguments);
var $invoiceHtml = this.$el.find('iframe#invoice_html');
var updateIframeSize = this._updateIframeSize.bind(this, $invoiceHtml);
$(window).on('resize', updateIframeSize);
var iframeDoc = $invoiceHtml[0].contentDocument || $invoiceHtml[0].contentWindow.document;
if (iframeDoc.readyState === 'complete') {
updateIframeSize();
} else {
$invoiceHtml.on('load', updateIframeSize);
}
return def;
},
//--------------------------------------------------------------------------
// Handlers
//--------------------------------------------------------------------------
/**
* Called when the iframe is loaded or the window is resized on customer portal.
* The goal is to expand the iframe height to display the full report without scrollbar.
*
* @private
* @param {object} $el: the iframe
*/
_updateIframeSize: function ($el) {
var $wrapwrap = $el.contents().find('div#wrapwrap');
// Set it to 0 first to handle the case where scrollHeight is too big for its content.
$el.height(0);
$el.height($wrapwrap[0].scrollHeight);
// scroll to the right place after iframe resize
if (!utils.isValidAnchor(window.location.hash)) {
return;
}
var $target = $(window.location.hash);
if (!$target.length) {
return;
}
dom.scrollTo($target[0], {duration: 0});
},
/**
* @private
* @param {MouseEvent} ev
*/
_onPrintInvoice: function (ev) {
ev.preventDefault();
var href = $(ev.currentTarget).attr('href');
this._printIframeContent(href);
},
});
});
odoo.define('account.ShowResequenceRenderer', function (require) {
"use strict";
const {Component} = owl;
const {useState} = owl.hooks;
const AbstractFieldOwl = require('web.AbstractFieldOwl');
const field_registry = require('web.field_registry_owl');
class ChangeLine extends Component {
}
ChangeLine.template = 'account.ResequenceChangeLine';
ChangeLine.props = ["changeLine", 'ordering'];
class ShowResequenceRenderer extends AbstractFieldOwl {
constructor(...args) {
super(...args);
this.data = this.value ? JSON.parse(this.value) : {
changeLines: [],
ordering: 'date',
};
}
async willUpdateProps(nextProps) {
await super.willUpdateProps(nextProps);
Object.assign(this.data, JSON.parse(this.value));
}
}
ShowResequenceRenderer.template = 'account.ResequenceRenderer';
ShowResequenceRenderer.components = {ChangeLine}
field_registry.add('account_resequence_widget', ShowResequenceRenderer);
return ShowResequenceRenderer;
});
odoo.define('account.hierarchy.selection', function (require) {
"use strict";
var core = require('web.core');
var relational_fields = require('web.relational_fields');
var _t = core._t;
var registry = require('web.field_registry');
var FieldSelection = relational_fields.FieldSelection;
var qweb = core.qweb;
var HierarchySelection = FieldSelection.extend({
_renderEdit: function () {
var self = this;
var prom = Promise.resolve()
if (!self.hierarchy_groups) {
prom = this._rpc({
model: 'account.account.type',
method: 'search_read',
kwargs: {
domain: [],
fields: ['id', 'internal_group', 'display_name'],
},
}).then(function (arg) {
self.values = _.map(arg, v => [v['id'], v['display_name']])
self.hierarchy_groups = [
{
'name': _t('Balance Sheet'),
'children': [
{
'name': _t('Assets'),
'ids': _.map(_.filter(arg, v => v['internal_group'] == 'asset'), v => v['id'])
},
{
'name': _t('Liabilities'),
'ids': _.map(_.filter(arg, v => v['internal_group'] == 'liability'), v => v['id'])
},
{
'name': _t('Equity'),
'ids': _.map(_.filter(arg, v => v['internal_group'] == 'equity'), v => v['id'])
},
],
},
{
'name': _t('Profit & Loss'),
'children': [
{
'name': _t('Income'),
'ids': _.map(_.filter(arg, v => v['internal_group'] == 'income'), v => v['id'])
},
{
'name': _t('Expense'),
'ids': _.map(_.filter(arg, v => v['internal_group'] == 'expense'), v => v['id'])
},
],
},
{
'name': _t('Other'),
'ids': _.map(_.filter(arg, v => !['asset', 'liability', 'equity', 'income', 'expense'].includes(v['internal_group'])), v => v['id'])
},
]
});
}
Promise.resolve(prom).then(function () {
self.$el.empty();
self._addHierarchy(self.$el, self.hierarchy_groups, 0);
var value = self.value;
if (self.field.type === 'many2one' && value) {
value = value.data.id;
}
self.$el.val(JSON.stringify(value));
});
},
_addHierarchy: function (el, group, level) {
var self = this;
_.each(group, function (item) {
var optgroup = $('<optgroup/>').attr(({
'label': $('<div/>').html('&nbsp;'.repeat(6 * level) + item['name']).text(),
}))
_.each(item['ids'], function (id) {
var value = _.find(self.values, v => v[0] == id)
optgroup.append($('<option/>', {
value: JSON.stringify(value[0]),
text: value[1],
}));
})
el.append(optgroup)
if (item['children']) {
self._addHierarchy(el, item['children'], level + 1);
}
})
}
});
registry.add("account_hierarchy_selection", HierarchySelection);
});
odoo.define('account.bank_statement', function (require) {
"use strict";
var KanbanController = require("web.KanbanController");
var ListController = require("web.ListController");
var includeDict = {
renderButtons: function () {
this._super.apply(this, arguments);
if (this.modelName === "account.bank.statement") {
var data = this.model.get(this.handle);
if (data.context.journal_type !== 'cash') {
this.$buttons.find('button.o_button_import').hide();
}
}
}
};
KanbanController.include(includeDict);
ListController.include(includeDict);
});
\ No newline at end of file
odoo.define('account.upload.bill.mixin', function (require) {
"use strict";
var core = require('web.core');
var _t = core._t;
var qweb = core.qweb;
var UploadBillMixin = {
start: function () {
// define a unique uploadId and a callback method
this.fileUploadID = _.uniqueId('account_bill_file_upload');
$(window).on(this.fileUploadID, this._onFileUploaded.bind(this));
return this._super.apply(this, arguments);
},
_onAddAttachment: function (ev) {
// Auto submit form once we've selected an attachment
var $input = $(ev.currentTarget).find('input.o_input_file');
if ($input.val() !== '') {
var $binaryForm = this.$('.o_vendor_bill_upload form.o_form_binary_form');
$binaryForm.submit();
}
},
_onFileUploaded: function () {
// Callback once attachment have been created, create a bill with attachment ids
var self = this;
var attachments = Array.prototype.slice.call(arguments, 1);
// Get id from result
var attachent_ids = attachments.reduce(function (filtered, record) {
if (record.id) {
filtered.push(record.id);
}
return filtered;
}, []);
return this._rpc({
model: 'account.journal',
method: 'create_invoice_from_attachment',
args: ["", attachent_ids],
context: this.initialState.context,
}).then(function (result) {
self.do_action(result);
});
},
_onUpload: function (event) {
var self = this;
// If hidden upload form don't exists, create it
var $formContainer = this.$('.o_content').find('.o_vendor_bill_upload');
if (!$formContainer.length) {
$formContainer = $(qweb.render('account.BillsHiddenUploadForm', {widget: this}));
$formContainer.appendTo(this.$('.o_content'));
}
// Trigger the input to select a file
this.$('.o_vendor_bill_upload .o_input_file').click();
},
}
return UploadBillMixin;
});
odoo.define('account.bills.tree', function (require) {
"use strict";
var core = require('web.core');
var ListController = require('web.ListController');
var ListView = require('web.ListView');
var UploadBillMixin = require('account.upload.bill.mixin');
var viewRegistry = require('web.view_registry');
var BillsListController = ListController.extend(UploadBillMixin, {
buttons_template: 'BillsListView.buttons',
events: _.extend({}, ListController.prototype.events, {
'click .o_button_upload_bill': '_onUpload',
'change .o_vendor_bill_upload .o_form_binary_form': '_onAddAttachment',
}),
});
var BillsListView = ListView.extend({
config: _.extend({}, ListView.prototype.config, {
Controller: BillsListController,
}),
});
viewRegistry.add('account_tree', BillsListView);
});
odoo.define('account.dashboard.kanban', function (require) {
"use strict";
var core = require('web.core');
var KanbanController = require('web.KanbanController');
var KanbanView = require('web.KanbanView');
var UploadBillMixin = require('account.upload.bill.mixin');
var viewRegistry = require('web.view_registry');
var DashboardKanbanController = KanbanController.extend(UploadBillMixin, {
events: _.extend({}, KanbanController.prototype.events, {
'click .o_button_upload_bill': '_onUpload',
'change .o_vendor_bill_upload .o_form_binary_form': '_onAddAttachment',
}),
/**
* We override _onUpload (from the upload bill mixin) to pass default_journal_id
* and default_move_type in context.
*
* @override
*/
_onUpload: function (event) {
var kanbanRecord = $(event.currentTarget).closest('.o_kanban_record').data('record');
this.initialState.context['default_journal_id'] = kanbanRecord.id;
if ($(event.currentTarget).attr('journal_type') == 'sale') {
this.initialState.context['default_move_type'] = 'out_invoice'
} else if ($(event.currentTarget).attr('journal_type') == 'purchase') {
this.initialState.context['default_move_type'] = 'in_invoice'
}
UploadBillMixin._onUpload.apply(this, arguments);
}
});
var DashboardKanbanView = KanbanView.extend({
config: _.extend({}, KanbanView.prototype.config, {
Controller: DashboardKanbanController,
}),
});
viewRegistry.add('account_dashboard_kanban', DashboardKanbanView);
});
odoo.define('account.ShowGroupedList', function (require) {
"use strict";
const {Component} = owl;
const {useState} = owl.hooks;
const AbstractFieldOwl = require('web.AbstractFieldOwl');
const field_registry = require('web.field_registry_owl');
class ListItem extends Component {
}
ListItem.template = 'account.GroupedItemTemplate';
ListItem.props = ["item_vals", "options"];
class ListGroup extends Component {
}
ListGroup.template = 'account.GroupedItemsTemplate';
ListGroup.components = {ListItem}
ListGroup.props = ["group_vals", "options"];
class ShowGroupedList extends AbstractFieldOwl {
constructor(...args) {
super(...args);
this.data = this.value ? JSON.parse(this.value) : {
groups_vals: [],
options: {
discarded_number: '',
columns: [],
},
};
}
async willUpdateProps(nextProps) {
await super.willUpdateProps(nextProps);
Object.assign(this.data, JSON.parse(this.value));
}
}
ShowGroupedList.template = 'account.GroupedListTemplate';
ShowGroupedList.components = {ListGroup}
field_registry.add('grouped_view_widget', ShowGroupedList);
return ShowGroupedList;
});
odoo.define('account.activity', function (require) {
"use strict";
var AbstractField = require('web.AbstractField');
var core = require('web.core');
var field_registry = require('web.field_registry');
var QWeb = core.qweb;
var _t = core._t;
var VatActivity = AbstractField.extend({
className: 'o_journal_activity_kanban',
events: {
'click .see_all_activities': '_onOpenAll',
'click .see_activity': '_onOpenActivity',
},
init: function () {
this.MAX_ACTIVITY_DISPLAY = 5;
this._super.apply(this, arguments);
},
//------------------------------------------------------------
// Private
//------------------------------------------------------------
_render: function () {
var self = this;
var info = JSON.parse(this.value);
if (!info) {
this.$el.html('');
return;
}
info.more_activities = false;
if (info.activities.length > this.MAX_ACTIVITY_DISPLAY) {
info.more_activities = true;
info.activities = info.activities.slice(0, this.MAX_ACTIVITY_DISPLAY);
}
this.$el.html(QWeb.render('accountJournalDashboardActivity', info));
},
_onOpenActivity: function (e) {
e.preventDefault();
var self = this;
self.do_action({
type: 'ir.actions.act_window',
name: _t('Journal Entry'),
target: 'current',
res_id: $(e.target).data('resId'),
res_model: 'account.move',
views: [[false, 'form']],
});
},
_onOpenAll: function (e) {
e.preventDefault();
var self = this;
self.do_action({
type: 'ir.actions.act_window',
name: _t('Journal Entries'),
res_model: 'account.move',
views: [[false, 'kanban'], [false, 'form']],
search_view_id: [false],
domain: [['journal_id', '=', self.res_id], ['activity_ids', '!=', false]],
});
}
})
field_registry.add('kanban_vat_activity', VatActivity);
return VatActivity;
});
odoo.define('account.section_and_note_backend', function (require) {
// The goal of this file is to contain JS hacks related to allowing
// section and note on sale order and invoice.
// [UPDATED] now also allows configuring products on sale order.
"use strict";
var FieldChar = require('web.basic_fields').FieldChar;
var FieldOne2Many = require('web.relational_fields').FieldOne2Many;
var fieldRegistry = require('web.field_registry');
var ListFieldText = require('web.basic_fields').ListFieldText;
var ListRenderer = require('web.ListRenderer');
var SectionAndNoteListRenderer = ListRenderer.extend({
/**
* We want section and note to take the whole line (except handle and trash)
* to look better and to hide the unnecessary fields.
*
* @override
*/
_renderBodyCell: function (record, node, index, options) {
var $cell = this._super.apply(this, arguments);
var isSection = record.data.display_type === 'line_section';
var isNote = record.data.display_type === 'line_note';
if (isSection || isNote) {
if (node.attrs.widget === "handle") {
return $cell;
} else if (node.attrs.name === "name") {
var nbrColumns = this._getNumberOfCols();
if (this.handleField) {
nbrColumns--;
}
if (this.addTrashIcon) {
nbrColumns--;
}
$cell.attr('colspan', nbrColumns);
} else {
$cell.removeClass('o_invisible_modifier');
return $cell.addClass('o_hidden');
}
}
return $cell;
},
/**
* We add the o_is_{display_type} class to allow custom behaviour both in JS and CSS.
*
* @override
*/
_renderRow: function (record, index) {
var $row = this._super.apply(this, arguments);
if (record.data.display_type) {
$row.addClass('o_is_' + record.data.display_type);
}
return $row;
},
/**
* We want to add .o_section_and_note_list_view on the table to have stronger CSS.
*
* @override
* @private
*/
_renderView: function () {
var self = this;
return this._super.apply(this, arguments).then(function () {
self.$('.o_list_table').addClass('o_section_and_note_list_view');
});
}
});
// We create a custom widget because this is the cleanest way to do it:
// to be sure this custom code will only impact selected fields having the widget
// and not applied to any other existing ListRenderer.
var SectionAndNoteFieldOne2Many = FieldOne2Many.extend({
/**
* We want to use our custom renderer for the list.
*
* @override
*/
_getRenderer: function () {
if (this.view.arch.tag === 'tree') {
return SectionAndNoteListRenderer;
}
return this._super.apply(this, arguments);
},
});
// This is a merge between a FieldText and a FieldChar.
// We want a FieldChar for section,
// and a FieldText for the rest (product and note).
var SectionAndNoteFieldText = function (parent, name, record, options) {
var isSection = record.data.display_type === 'line_section';
var Constructor = isSection ? FieldChar : ListFieldText;
return new Constructor(parent, name, record, options);
};
fieldRegistry.add('section_and_note_one2many', SectionAndNoteFieldOne2Many);
fieldRegistry.add('section_and_note_text', SectionAndNoteFieldText);
return SectionAndNoteListRenderer;
});
odoo.define('account.tax_group', function (require) {
"use strict";
var core = require('web.core');
var session = require('web.session');
var fieldRegistry = require('web.field_registry');
var AbstractField = require('web.AbstractField');
var fieldUtils = require('web.field_utils');
var QWeb = core.qweb;
var TaxGroupCustomField = AbstractField.extend({
events: {
'click .tax_group_edit': '_onClick',
'keydown .oe_tax_group_editable .tax_group_edit_input input': '_onKeydown',
'blur .oe_tax_group_editable .tax_group_edit_input input': '_onBlur',
},
//--------------------------------------------------------------------------
// Private
//--------------------------------------------------------------------------
/**
* This method is called by "_setTaxGroups". It is
* responsible for calculating taxes based on
* tax groups and triggering an event to
* notify the ORM of a change.
*
* @param {Id} taxGroupId
* @param {Float} deltaAmount
*/
_changeTaxValueByTaxGroup: function (taxGroupId, deltaAmount) {
const self = this;
// Search for the first tax line with the same tax group and modify its value
function applyChange(line_id) {
let debitAmount = 0;
let creditAmount = 0;
let amount_currency = 0;
if (line_id.data.currency_id) { // If multi currency enable
if (self.record.data.move_type === "in_invoice") {
amount_currency = line_id.data.amount_currency - deltaAmount;
} else {
amount_currency = line_id.data.amount_currency + deltaAmount;
}
} else {
let balance = line_id.data.price_subtotal;
balance -= deltaAmount;
if (self.record.data.move_type === "in_invoice") { // For vendor bill
if (balance > 0) {
debitAmount = balance;
} else if (balance < 0) {
creditAmount = -balance;
}
} else { // For refund
if (balance > 0) {
creditAmount = balance;
} else if (balance < 0) {
debitAmount = -balance;
}
}
}
// Trigger ORM
self.trigger_up('field_changed', {
dataPointID: self.record.id,
changes: {
line_ids: {
operation: "UPDATE",
id: line_id.id,
data: {amount_currency: amount_currency, debit: debitAmount, credit: creditAmount}
}
}, // account.move change
initialEvent: {
dataPointID: line_id.id,
changes: {amount_currency: amount_currency, debit: debitAmount, credit: creditAmount},
}, // account.move.line change
});
}
let line_id = self.record.data.line_ids.data.find(elem => elem.data.tax_group_id && elem.data.tax_group_id.data.id === taxGroupId);
if (line_id) {
applyChange(line_id);
} else {
const {limit, id, count} = self.record.data.line_ids;
let offset = count - limit;
self.trigger_up('load', {
id,
limit,
offset,
on_success: value => {
line_id = value.data.find(elem => elem.data.tax_group_id && elem.data.tax_group_id.data.id === taxGroupId);
applyChange(line_id);
},
});
}
},
/**
* This method checks that the document where the widget
* is located is of the "in_invoice" or "in_refund" type.
* This makes it possible to know if it is a purchase
* document.
*
* @returns boolean (true if the invoice is a purchase document)
*/
_isPurchaseDocument: function () {
return this.record.data.move_type === "in_invoice" || this.record.data.move_type === 'in_refund';
},
/**
* This method is part of the widget life cycle and allows you to render
* the widget.
*
* @private
* @override
*/
_render: function () {
var self = this;
// Display the pencil and allow the event to click and edit only on purchase that are not posted and in edit mode.
// since the field is readonly its mode will always be readonly. Therefore we have to use a trick by checking the
// formRenderer (the parent) and check if it is in edit in order to know the correct mode.
var displayEditWidget = self._isPurchaseDocument() && this.record.data.state === 'draft' && this.getParent().mode === 'edit';
this.$el.html($(QWeb.render('AccountTaxGroupTemplate', {
lines: self.value,
displayEditWidget: displayEditWidget,
})));
},
//--------------------------------------------------------------------------
// Handler
//--------------------------------------------------------------------------
/**
* This method is called when the user is in edit mode and
* leaves the <input> field. Then, we execute the code that
* modifies the information.
*
* @param {event} ev
*/
_onBlur: function (ev) {
ev.preventDefault();
var $input = $(ev.target);
var newValue = $input.val();
var currency = session.get_currency(this.record.data.currency_id.data.id);
try {
newValue = fieldUtils.parse.float(newValue); // Need a float for format the value.
newValue = fieldUtils.format.float(newValue, null, {digits: currency.digits}); // return a string rounded to currency precision
newValue = fieldUtils.parse.float(newValue); // convert back to Float to compare with oldValue to know if value has changed
} catch (err) {
$input.addClass('o_field_invalid');
return;
}
var oldValue = $input.data('originalValue');
if (newValue === oldValue || newValue === 0) {
return this._render();
}
var taxGroupId = $input.parents('.oe_tax_group_editable').data('taxGroupId');
this._changeTaxValueByTaxGroup(taxGroupId, oldValue - newValue);
},
/**
* This method is called when the user clicks on a specific <td>.
* it will hide the edit button and display the field to be edited.
*
* @param {event} ev
*/
_onClick: function (ev) {
ev.preventDefault();
var $taxGroupElement = $(ev.target).parents('.oe_tax_group_editable');
// Show input and hide previous element
$taxGroupElement.find('.tax_group_edit').addClass('d-none');
$taxGroupElement.find('.tax_group_edit_input').removeClass('d-none');
var $input = $taxGroupElement.find('.tax_group_edit_input input');
// Get original value and display it in user locale in the input
var formatedOriginalValue = fieldUtils.format.float($input.data('originalValue'), {}, {});
$input.focus(); // Focus the input
$input.val(formatedOriginalValue); //add value in user locale to the input
},
/**
* This method is called when the user is in edit mode and pressing
* a key on his keyboard. If this key corresponds to ENTER or TAB,
* the code that modifies the information is executed.
*
* @param {event} ev
*/
_onKeydown: function (ev) {
switch (ev.which) {
// Trigger only if the user clicks on ENTER or on TAB.
case $.ui.keyCode.ENTER:
case $.ui.keyCode.TAB:
// trigger blur to prevent the code being executed twice
$(ev.target).blur();
}
},
});
fieldRegistry.add('tax-group-custom-field', TaxGroupCustomField)
});
odoo.define('account.tour', function (require) {
"use strict";
var core = require('web.core');
var tour = require('web_tour.tour');
var _t = core._t;
tour.register('account_tour', {
url: "/web",
sequence: 60,
}, [
...tour.stepUtils.goToAppSteps('account.menu_finance', _t('Send invoices to your customers in no time with the <b>Invoicing app</b>.')),
{
trigger: "a.o_onboarding_step_action[data-method=action_open_base_onboarding_company]",
content: _t("Start by checking your company's data."),
position: "bottom",
}, {
trigger: "button[name=action_save_onboarding_company_step]",
extra_trigger: "a.o_onboarding_step_action[data-method=action_open_base_onboarding_company]",
content: _t("Looks good. Let's continue."),
position: "bottom",
}, {
trigger: "a.o_onboarding_step_action[data-method=action_open_base_document_layout]",
content: _t("Customize your layout."),
position: "bottom",
}, {
trigger: "button[name=document_layout_save]",
extra_trigger: "a.o_onboarding_step_action[data-method=action_open_base_document_layout]",
content: _t("Once everything is as you want it, validate."),
position: "top",
}, {
trigger: "a.o_onboarding_step_action[data-method=action_open_account_onboarding_create_invoice]",
content: _t("Now, we'll create your first invoice."),
position: "bottom",
}, {
trigger: "div[name=partner_id] input",
extra_trigger: "[name=move_type][raw-value=out_invoice]",
content: _t("Write a company name to <b>create one</b> or <b>see suggestions</b>."),
position: "bottom",
}, {
trigger: ".o_m2o_dropdown_option a:contains('Create')",
extra_trigger: "[name=move_type][raw-value=out_invoice]",
content: _t("Select first partner"),
auto: true,
}, {
trigger: ".modal-content button.btn-primary",
extra_trigger: "[name=move_type][raw-value=out_invoice]",
content: _t("Once everything is set, you are good to continue. You will be able to edit this later in the <b>Customers</b> menu."),
auto: true,
}, {
trigger: "div[name=invoice_line_ids] .o_field_x2many_list_row_add a:not([data-context])",
extra_trigger: "[name=move_type][raw-value=out_invoice]",
content: _t("Add a line to your invoice"),
}, {
trigger: "div[name=invoice_line_ids] textarea[name=name]",
extra_trigger: "[name=move_type][raw-value=out_invoice]",
content: _t("Fill in the details of the line."),
position: "bottom",
}, {
trigger: "div[name=invoice_line_ids] input[name=price_unit]",
extra_trigger: "[name=move_type][raw-value=out_invoice]",
content: _t("Set a price"),
position: "bottom",
run: 'text 100',
}, {
trigger: "button[name=action_post]",
extra_trigger: "[name=move_type][raw-value=out_invoice]",
content: _t("Once your invoice is ready, press CONFIRM."),
}, {
trigger: "button[name=action_invoice_sent]",
extra_trigger: "[name=move_type][raw-value=out_invoice]",
content: _t("Send the invoice and check what the customer will receive."),
}, {
trigger: "input[name=email]",
extra_trigger: "[name=move_type][raw-value=out_invoice]",
content: _t("Write here <b>your own email address</b> to test the flow."),
run: 'text customer@example.com',
auto: true,
}, {
trigger: ".modal-content button.btn-primary",
extra_trigger: "[name=move_type][raw-value=out_invoice]",
content: _t("Validate."),
auto: true,
}, {
trigger: "button[name=send_and_print_action]",
extra_trigger: "[name=move_type][raw-value=out_invoice]",
content: _t("Let's send the invoice."),
position: "top"
}
]);
});
.o_journal_activity_kanban {
display: block;
.align_activity_center {
width: 100%;
align-items: center;
margin-bottom: 5px;
}
}
\ No newline at end of file
.o_kanban_view.o_kanban_dashboard.o_account_kanban {
&.o_kanban_ungrouped .o_account_dashboard_header {
margin: (0 - $o-kanban-record-margin) ($o-kanban-record-margin - $o-horizontal-padding) $o-kanban-record-margin;
}
.o_account_dashboard_header {
flex: 1 0 100%;
flex-flow: column nowrap;
align-self: flex-start;
width: 100%;
height: auto; // cancel o_form_view height 100%, which hides the help tip message at the bottom of the screen
min-height: 0%; // cancel o_form_view min-height 100%, which hides the help tip message at the bottom of the screen
background-color: $o-view-background-color;
.o_form_statusbar {
padding-right: $o-horizontal-padding;
}
h4 {
font-size: $font-size-base;
font-weight: 500;
}
.fa-gift {
color: #eeeeee;
&:hover {
color: #555555;
}
}
.o_arrow_button.btn-secondary {
color: $text-muted;
text-transform: none;
font-weight: 500;
.o_account_dashboard_index {
color: gray('900');
}
&.o_action_done {
color: gray('900');
background-color: gray('200');
&:after {
border-left-color: gray('200');
}
.fa-check {
color: theme-color('success');
}
}
&:last-of-type {
margin-left: $o-horizontal-padding;
padding-left: $o-horizontal-padding*.5;
border-left: 1px solid gray('300');
}
}
}
}
.o_kanban_view.o_kanban_dashboard.o_account_kanban {
.o_kanban_record {
@include media-breakpoint-up(sm) {
.oe_kanban_action_button {
display: block;
margin-bottom: 5px;
}
}
.o_kanban_card_settings {
padding-top: $o-horizontal-padding/2;
padding-bottom: $o-horizontal-padding/2;
border-top: 1px solid;
border-color: $o-brand-lightsecondary;
}
.o_dashboard_star {
font-size: 12px;
&.fa-star-o {
color: $o-main-color-muted;
&:hover {
color: gold;
}
}
&.fa-star {
color: gold;
}
}
.o_dashboard_graph {
margin-bottom: -$o-horizontal-padding/2;
}
}
&.o_kanban_ungrouped {
.o_kanban_record {
width: 450px;
}
}
.o_kanban_group {
&:not(.o_column_folded) {
width: 450px + 2*$o-kanban-group-padding;
@include media-breakpoint-down(sm) {
width: 100%;
}
}
}
}
// Style for the widget "dashboard_graph"
.o_dashboard_graph {
position: relative;
margin: 16px -16px;
canvas {
height: 75px;
}
}
.o_sample_data .o_dashboard_graph.o_graph_linechart > svg g.nv-linesWrap g.nv-group.nv-series-0 {
fill: gray !important;
opacity: 0.1;
}
.progress-reconciliation {
.progress-bar {
font-size: 1.08333333rem;
height: 14px;
background-color: $o-enterprise-color;
span {
display: contents;
}
}
}
.o_reconciliation {
.o_filter_input_wrapper {
position: relative;
width: 150px;
margin: 0.5rem !important;
.searchIcon {
position: absolute;
right: 10px;
}
.o_filter_input {
border: none;
border-bottom: 1px black solid;
}
}
.import_to_suspense {
margin: 0.5rem !important;
}
.notification_area {
clear: both;
}
.o_view_noreconciliation {
max-width: none;
padding: 0 10%;
color: $o-main-color-muted;
font-size: 125%;
}
.accounting_view {
width: 100%;
.cell_left {
border-right: 1px solid #333;
padding-right: 5px;
}
.edit_amount {
margin-left: 20px;
color: #bbb;
}
.cell:hover .edit_amount {
color: #00A09D;
}
.strike_amount {
text-decoration: line-through;
}
tbody tr:hover .cell_account_code::before {
content: "\f068";
font-family: FontAwesome;
position: relative;
margin-left: -17px;
left: -4px;
line-height: 0;
padding: 3px 2px 5px 5px;
}
}
.o_multi_currency {
margin-right: 5px;
&.o_multi_currency_color_0 {
color: #dd6666;
}
&.o_multi_currency_color_1 {
color: #aaaaaa;
}
&.o_multi_currency_color_2 {
color: #66dd66;
}
&.o_multi_currency_color_3 {
color: #6666dd;
}
&.o_multi_currency_color_4 {
color: #dddd66;
}
&.o_multi_currency_color_5 {
color: #dd66dd;
}
&.o_multi_currency_color_6 {
color: #66dddd;
}
&.o_multi_currency_color_7 {
color: #aaa333;
}
}
.o_reconciliation_line {
margin-bottom: 30px;
table {
width: 100%;
vertical-align: top;
}
tbody tr {
cursor: pointer;
}
tr.already_reconciled {
color: $o-account-info-color;
}
tr.invalid {
text-decoration: line-through;
}
td {
padding: 1px 2px;
}
thead td {
border-top: $o-account-light-border;
padding-top: 4px;
padding-bottom: 5px;
background-color: $o-account-initial-line-background;
}
tfoot td {
color: #bbb;
}
/* columns */
.cell_action {
width: 15px;
color: gray('700');
background: #fff;
border: 0;
text-align: center;
.fa-add-remove:before {
content: "";
}
}
tr:hover .cell_action .fa-add-remove:before {
content: "\f068";
}
.is_tax .cell_action .fa-add-remove:before {
position: relative;
top: -18px;
}
.cell_account_code {
width: 80px;
padding-left: 5px;
}
.cell_due_date {
width: 100px;
}
.cell_label {
width: auto;
}
.cell_left {
padding-right: 5px;
}
.cell_right, .cell_left {
text-align: right;
width: 120px;
}
.cell_info_popover {
text-align: right;
width: 15px;
color: #ccc;
&:empty {
padding: 0;
width: 0;
}
}
table.accounting_view {
.cell_right, .cell_left, .cell_label, .cell_due_date, .cell_account_code, .cell_info_popover {
box-shadow: 0 1px 0 #EAEAEA;
}
}
/* info popover */
.popover {
max-width: none;
}
table.details {
vertical-align: top;
td:first-child {
vertical-align: top;
padding-right: 10px;
font-weight: bold;
}
}
tr.one_line_info {
td {
padding-top: 10px;
text-align: center;
color: $o-account-info-color;
}
}
/* Icons */
.toggle_match, .toggle_create {
transform: rotate(0deg);
transition: transform 300ms ease 0s;
}
.visible_toggle, &[data-mode="match"] .toggle_match, &[data-mode="create"] .toggle_create {
visibility: visible !important;
transform: rotate(90deg);
}
.toggle_create {
font-size: 10px;
}
/* Match view & Create view */
> .o_notebook {
display: none;
> .o_notebook_headers {
margin-right: 0;
margin-left: 0;
}
}
> .o_notebook > .tab-content > div {
border: 1px solid #ddd;
border-top: 0;
}
> .o_notebook .match table tr:hover {
background-color: #eee;
}
&:not([data-mode="inactive"]) > .o_notebook {
display: block;
}
&:not(:focus-within) .o_web_accesskey_overlay {
display: none;
}
&:focus caption .o_buttons button {
outline: none;
box-shadow: 4px 4px 4px 0px $o-enterprise-color;
}
&:focus {
outline: none;
box-shadow: 0 0 0 0;
}
}
.o_reconcile_models .btn-primary {
margin: 0 2px 3px 0;
}
/* Match view */
.match {
.cell_action .fa-add-remove:before {
content: "";
}
tr:hover .cell_action .fa-add-remove:before {
content: "\f067";
}
.match_controls {
padding: 5px 0 5px ($o-account-action-col-width+$o-account-main-table-borders-padding);
.filter {
width: 240px;
display: inline-block;
}
.fa-chevron-left, .fa-chevron-right {
display: inline-block;
cursor: pointer;
}
.fa-chevron-left {
margin-right: 10px;
}
.fa-chevron-left.disabled, .fa-chevron-right.disabled {
color: #ddd;
cursor: default;
}
}
.show_more {
display: inline-block;
margin-left: ($o-account-action-col-width+$o-account-main-table-borders-padding);
margin-top: 5px;
}
}
/* Create view */
.create {
> div > div.quick_add > .o_reconcile_models {
max-width: 100%;
max-height: 70px;
flex-wrap: wrap;
overflow: auto;
& > * {
flex-grow: 0;
}
}
.quick_add {
margin-bottom: 7px;
padding: 0 8px;
}
.o_group table.o_group_col_6 {
width: 49%;
margin: 0;
vertical-align: top;
}
.o_group table.o_group_col_6:first-child {
margin-left: 8px;
}
.btn {
padding-top: 0;
padding-bottom: 0;
}
.add_line_container {
text-align: center;
clear: both;
color: $o-enterprise-primary-color;
cursor: pointer;
}
}
.o_notebook .tab-content > .tab-pane {
padding: 5px 0;
}
}
/*Manual Reconciliation*/
.o_manual_statement {
.accounting_view {
td[colspan="3"] span:first-child {
width: 100%;
display: inline-block;
}
td[colspan="2"] {
border-bottom: 1px solid #333;
text-align: center;
width: 240px;
}
.do_partial_reconcile_true {
display: none;
}
}
}
// This is rtl language specific fix
// It will flip the fa-fa play icon in left direction
.o_rtl {
.o_reconciliation {
.o_reconciliation_line {
.toggle_match, .toggle_create {
transform: rotate(180deg);
transition: transform 300ms;
}
.visible_toggle, &[data-mode="match"] .toggle_match, &[data-mode="create"] .toggle_create {
transform: rotate(270deg);
}
}
}
}
.o_search_panel.account_root {
flex: 0 0 50px;
padding: 6px;
scrollbar-width: thin;
.o_search_panel_section_header {
display: none;
}
.list-group-item span.o_search_panel_label_title {
display: contents;
}
.o_search_panel_category_value {
header {
margin-left: 0;
padding-left: 0;
}
.o_search_panel_category_value .o_toggle_fold {
width: 0.3rem;
}
}
&::-webkit-scrollbar {
width: 4px;
}
&::-webkit-scrollbar-thumb {
background: lightgray;
}
}
// The goal of this file is to contain CSS hacks related to allowing
// section and note on sale order and invoice.
table.o_section_and_note_list_view tr.o_data_row.o_is_line_note,
table.o_section_and_note_list_view tr.o_data_row.o_is_line_note textarea[name="name"],
div.oe_kanban_card.o_is_line_note {
font-style: italic;
}
table.o_section_and_note_list_view tr.o_data_row.o_is_line_section,
div.oe_kanban_card.o_is_line_section {
font-weight: bold;
background-color: #DDDDDD;
}
table.o_section_and_note_list_view tr.o_data_row.o_is_line_section {
border-top: 1px solid #BBB;
border-bottom: 1px solid #BBB;
}
table.o_section_and_note_list_view tr.o_data_row {
&.o_is_line_note,
&.o_is_line_section {
td {
// There is an undeterministic CSS behaviour in Chrome related to
// the combination of the row's and its children's borders.
border: none !important;
}
}
}
$o-account-action-col-width: 15px;
$o-account-main-table-borders-padding: 3px;
$o-account-light-border: 1px solid #bbb;
$o-account-initial-line-background: #f0f0f0;
$o-account-info-color: #44c;
@keyframes animate-red {
0% {
color: red;
}
100% {
color: inherit;
}
}
.animate {
animation: animate-red 1s ease;
}
<?xml version="1.0" encoding="UTF-8"?>
<templates>
<t t-name="accountJournalDashboardActivity">
<t t-foreach="activities" t-as="activity">
<div class="row">
<div class="col-8 o_mail_activity">
<a href="#"
t-att-class="(activity.status == 'late' ? 'o_activity_color_overdue ' : ' ') + (activity.activity_category == 'tax_report' ? 'o_open_vat_report' : 'see_activity')"
t-att-data-res-id="activity.res_id" t-att-data-id="activity.id"
t-att-data-model="activity.res_model">
<t t-esc="activity.name"/>
</a>
</div>
<div class="col-4 text-right">
<span>
<t t-esc="activity.date"/>
</span>
</div>
</div>
</t>
<a t-if="more_activities" class="pull-right see_all_activities" href="#">See all activities</a>
</t>
</templates>
<?xml version="1.0" encoding="UTF-8"?>
<templates xml:space="preserve">
<t t-name="ShowPaymentInfo">
<div>
<t t-if="outstanding">
<div>
<strong class="float-left" id="outstanding"><t t-esc="title"></t></strong>
</div>
</t>
<table style="width:100%;">
<t t-foreach="lines" t-as="line">
<tr>
<t t-if="outstanding">
<td>
<a title="assign to invoice" role="button"
class="oe_form_field btn btn-link outstanding_credit_assign" t-att-data-id="line.id"
style="margin-right: 10px;" href="#" data-toggle="tooltip">Add</a>
</td>
<td style="max-width: 30em;">
<div class="oe_form_field"
style="margin-right: 30px; text-overflow: ellipsis; overflow: hidden; white-space: nowrap;"
t-att-title="line.date" data-toggle="tooltip"><t t-esc="line.journal_name"></t></div>
</td>
</t>
<t t-if="!outstanding">
<td>
<a role="button" tabindex="0" class="js_payment_info fa fa-info-circle"
t-att-index="line.index" style="margin-right:5px;" aria-label="Info" title="Payment Info"
data-toggle="tooltip"></a>
</td>
<td>
<i class="o_field_widget text-right o_payment_label">Paid on <t t-esc="line.date"></t></i>
</td>
</t>
<td style="text-align:right;">
<span class="oe_form_field oe_form_field_float oe_form_field_monetary"
style="margin-left: -10px;">
<t t-if="line.position === 'before'">
<t t-esc="line.currency"/>
</t>
<t t-esc="line.amount"></t>
<t t-if="line.position === 'after'">
<t t-esc="line.currency"/>
</t>
</span>
</td>
</tr>
</t>
</table>
</div>
</t>
<t t-name="PaymentPopOver">
<div>
<table>
<tr>
<td><strong>Amount: </strong></td>
<td>
<t t-if="position === 'before'">
<t t-esc="currency"/>
</t>
<t t-esc="amount"></t>
<t t-if="position === 'after'">
<t t-esc="currency"/>
</t>
</td>
</tr>
<tr>
<td><strong>Memo: </strong></td>
<td>
<div style="width: 200px; word-wrap: break-word">
<t t-esc="ref"/>
</div>
</td>
</tr>
<tr>
<td><strong>Date: </strong></td>
<td><t t-esc="date"/></td>
</tr>
<tr>
<td><strong>Payment Journal: </strong></td>
<td><t t-esc="journal_name"/>
<span t-if="payment_method_name"> (<t t-esc="payment_method_name"/>)</span></td>
</tr>
</table>
</div>
<button class="btn btn-sm btn-primary js_unreconcile_payment float-left" t-att-partial-id="partial_id"
t-att-payment-id="payment_id" t-att-move-id="move_id" style="margin-top:5px; margin-bottom:5px;"
groups="account.group_account_invoice">Unreconcile</button>
<button class="btn btn-sm btn-secondary js_open_payment float-right" t-att-payment-id="account_payment_id"
t-att-move-id="move_id" style="margin-top:5px; margin-bottom:5px;">View</button>
</t>
</templates>
<?xml version="1.0" encoding="utf-8"?>
<templates>
<div t-name="account.ResequenceRenderer" owl="1" class="d-block">
<table t-if="data.changeLines.length" class="table table-sm">
<thead>
<tr>
<th>Date</th>
<th>Before</th>
<th>After</th>
</tr>
</thead>
<tbody t-foreach="data.changeLines" t-as="changeLine" t-key="changeLine.id">
<ChangeLine changeLine="changeLine" ordering="data.ordering"/>
</tbody>
</table>
</div>
<t t-name="account.ResequenceChangeLine" owl="1">
<tr>
<td t-esc="props.changeLine.date"/>
<td t-esc="props.changeLine.current_name"/>
<td t-if="props.ordering == 'keep'" t-esc="props.changeLine.new_by_name"
t-attf-class="{{ props.changeLine.new_by_name != props.changeLine.new_by_date ? 'animate' : ''}}"/>
<td t-else="" t-esc="props.changeLine.new_by_date"
t-attf-class="{{ props.changeLine.new_by_name != props.changeLine.new_by_date ? 'animate' : ''}}"/>
</tr>
</t>
</templates>
<?xml version="1.0" encoding="UTF-8"?>
<templates>
<t t-name="account.BillsHiddenUploadForm">
<div class="d-none o_vendor_bill_upload">
<t t-call="HiddenInputFile">
<t t-set="multi_upload" t-value="true"/>
<t t-set="fileupload_id" t-value="widget.fileUploadID"/>
<t t-set="fileupload_action" t-translation="off">/web/binary/upload_attachment</t>
<input type="hidden" name="model" value=""/>
<input type="hidden" name="id" value="0"/>
</t>
</div>
</t>
<t t-extend="ListView.buttons" t-name="BillsListView.buttons">
<t t-jquery="button.o_list_button_add" t-operation="after">
<button type="button" class="btn btn-secondary o_button_upload_bill">
Upload
</button>
</t>
</t>
</templates>
<?xml version="1.0" encoding="utf-8"?>
<templates>
<div t-name="account.GroupedListTemplate" owl="1" class="d-block">
<table t-if="data.groups_vals.length"
class="table table-sm o_list_table table table-sm table-hover table-striped o_list_table_grouped">
<thead>
<tr>
<t t-foreach="data.options.columns" t-as="col">
<th t-esc="col['label']" t-attf-class="{{col['class']}}"/>
</t>
</tr>
</thead>
<t t-foreach="data.groups_vals" t-as="group_vals">
<ListGroup group_vals="group_vals" options="data.options"/>
</t>
</table>
<t t-if="data.options.discarded_number">
<span>
<t t-esc="data.options.discarded_number"/>
are not shown in the preview
</span>
</t>
</div>
<tbody t-name="account.GroupedItemsTemplate" owl="1">
<tr style="background-color: #dee2e6;">
<td t-attf-colspan="{{props.options.columns.length}}">
<t t-esc="props.group_vals.group_name"/>
</td>
</tr>
<t t-foreach="props.group_vals.items_vals" t-as="item_vals">
<ListItem item_vals="item_vals[2]" options="props.options"/>
</t>
</tbody>
<tr t-name="account.GroupedItemTemplate" owl="1">
<t t-foreach="props.options.columns" t-as="col">
<td t-esc="props.item_vals[col['field']]" t-attf-class="{{col['class']}}"/>
</t>
</tr>
</templates>
<?xml version='1.0' encoding='utf-8'?>
<templates>
<t t-name="AccountTaxGroupTemplate">
<table class="o_group o_inner_group oe_subtotal_footer border-0 my-0" style="min-width: 100%;">
<tbody>
<t t-foreach="lines" t-as="line">
<tr>
<td class="o_td_label oe_tax_group_name">
<label class="o_form_label" t-esc="line[0]"/>
</td>
<td class="oe_tax_group_editable" t-att-data-tax-group-id="line[6]">
<t t-if="displayEditWidget and line[1] !== 0">
<span class="tax_group_edit">
<i class="fa fa-pencil"></i>
<span class="oe_tax_group_amount_value">
<t t-esc="line[3]"/>
</span>
</span>
<span class="tax_group_edit_input d-none">
<input type="text" class="o_field_float o_field_number o_input"
t-att-data-original-value="line[1]"/>
</span>
</t>
<t t-if="!displayEditWidget or line[1] === 0">
<span class="oe_tax_group_amount_value">
<t t-esc="line[3]"/>
</span>
</t>
</td>
</tr>
</t>
</tbody>
</table>
</t>
</templates>
odoo.define('account.reconciliation_field_tests', function (require) {
"use strict";
var FormView = require('web.FormView');
var testUtils = require('web.test_utils');
var createView = testUtils.createView;
QUnit.module('account', {
beforeEach: function () {
this.data = {
'account.move': {
fields: {
payments_widget: {string: "payments_widget data", type: "char"},
outstanding_credits_debits_widget: {
string: "outstanding_credits_debits_widget data",
type: "char"
},
},
records: [{
id: 1,
payments_widget: '{"content": [{"digits": [69, 2], "currency": "$", "amount": 555.0, "name": "Customer Payment: INV/2017/0004", "date": "2017-04-25", "position": "before", "ref": "BNK1/2017/0003 (INV/2017/0004)", "payment_id": 22, "move_id": 10, "partial_id": 38, "journal_name": "Bank"}], "outstanding": false, "title": "Less Payment"}',
outstanding_credits_debits_widget: '{"content": [{"digits": [69, 2], "currency": "$", "amount": 100.0, "journal_name": "INV/2017/0004", "position": "before", "id": 20}], "move_id": 4, "outstanding": true, "title": "Outstanding credits"}',
}]
},
};
}
}, function () {
QUnit.module('Reconciliation');
QUnit.test('Reconciliation form field', async function (assert) {
assert.expect(5);
var form = await createView({
View: FormView,
model: 'account.move',
data: this.data,
arch: '<form>' +
'<field name="outstanding_credits_debits_widget" widget="payment"/>' +
'<field name="payments_widget" widget="payment"/>' +
'</form>',
res_id: 1,
mockRPC: function (route, args) {
if (args.method === 'js_remove_outstanding_partial') {
assert.deepEqual(args.args, [10, 38], "should call js_remove_outstanding_partial {warning: required focus}");
return Promise.resolve();
}
if (args.method === 'js_assign_outstanding_line') {
assert.deepEqual(args.args, [4, 20], "should call js_assign_outstanding_line {warning: required focus}");
return Promise.resolve();
}
return this._super.apply(this, arguments);
},
intercepts: {
do_action: function (event) {
assert.deepEqual(event.data.action, {
'type': 'ir.actions.act_window',
'res_model': 'account.move',
'res_id': 10,
'views': [[false, 'form']],
'target': 'current'
},
"should open the form view");
},
},
});
assert.strictEqual(form.$('.o_field_widget[name="payments_widget"]').text().replace(/[\s\n\r]+/g, ' '),
" Paid on 04/25/2017 $ 555.00 ",
"should display payment information");
form.$('.o_field_widget[name="outstanding_credits_debits_widget"] .outstanding_credit_assign').trigger('click');
assert.strictEqual(form.$('.o_field_widget[name="outstanding_credits_debits_widget"]').text().replace(/[\s\n\r]+/g, ' '),
" Outstanding credits Add INV/2017/0004 $ 100.00 ",
"should display outstanding information");
form.$('.o_field_widget[name="payments_widget"] .js_payment_info').trigger('focus');
form.$('.popover .js_open_payment').trigger('click');
form.$('.o_field_widget[name="payments_widget"] .js_payment_info').trigger('focus');
form.$('.popover .js_unreconcile_payment').trigger('click');
form.destroy();
});
});
});
odoo.define('account.section_and_note_tests', function (require) {
"use strict";
var FormView = require('web.FormView');
var testUtils = require('web.test_utils');
var createView = testUtils.createView;
QUnit.module('section_and_note', {
beforeEach: function () {
this.data = {
invoice: {
fields: {
invoice_line_ids: {
string: "Lines",
type: 'one2many',
relation: 'invoice_line',
relation_field: 'invoice_id'
},
},
records: [
{id: 1, invoice_line_ids: [1, 2]},
],
},
invoice_line: {
fields: {
display_type: {
string: 'Type',
type: 'selection',
selection: [['line_section', "Section"], ['line_note', "Note"]]
},
invoice_id: {
string: "Invoice",
type: 'many2one',
relation: 'invoice'
},
name: {
string: "Name",
type: 'text'
},
},
records: [
{id: 1, display_type: false, invoice_id: 1, name: 'product\n2 lines'},
{id: 2, display_type: 'line_section', invoice_id: 1, name: 'section'},
]
},
};
},
}, function () {
QUnit.test('correct display of section and note fields', async function (assert) {
assert.expect(5);
var form = await createView({
View: FormView,
model: 'invoice',
data: this.data,
arch: '<form>' +
'<field name="invoice_line_ids" widget="section_and_note_one2many"/>' +
'</form>',
archs: {
'invoice_line,false,list': '<tree editable="bottom">' +
'<field name="display_type" invisible="1"/>' +
'<field name="name" widget="section_and_note_text"/>' +
'</tree>',
},
res_id: 1,
});
assert.hasClass(form.$('[name="invoice_line_ids"] table'), 'o_section_and_note_list_view');
// section should be displayed correctly
var $tr0 = form.$('tr.o_data_row:eq(0)');
assert.doesNotHaveClass($tr0, 'o_is_line_section',
"should not have a section class");
var $tr1 = form.$('tr.o_data_row:eq(1)');
assert.hasClass($tr1, 'o_is_line_section',
"should have a section class");
// enter edit mode
await testUtils.form.clickEdit(form);
// editing line should be textarea
$tr0 = form.$('tr.o_data_row:eq(0)');
await testUtils.dom.click($tr0.find('td.o_data_cell'));
assert.containsOnce($tr0, 'td.o_data_cell textarea[name="name"]',
"editing line should be textarea");
// editing section should be input
$tr1 = form.$('tr.o_data_row:eq(1)');
await testUtils.dom.click($tr1.find('td.o_data_cell'));
assert.containsOnce($tr1, 'td.o_data_cell input[name="name"]',
"editing section should be input");
form.destroy();
});
});
});
odoo.define('account.dashboard.setup.tour', function (require) {
"use strict";
var core = require('web.core');
var tour = require('web_tour.tour');
var _t = core._t;
tour.register('account_render_report', {
test: true,
url: '/web',
}, [tour.stepUtils.showAppsMenuItem(),
{
id: 'account_menu_click',
trigger: '.o_app[data-menu-xmlid="account.menu_finance"]',
position: 'bottom',
}, {
trigger: '.o_data_row:first',
extra_trigger: '.breadcrumb',
}, {
trigger: '.o_control_panel button:contains("' + _t('Print') + '")',
}, {
trigger: '.o_control_panel .o_dropdown_menu a:contains("' + _t('Invoices without Payment') + '")',
}, {
trigger: 'iframe .o_report_layout_standard h2',
content: 'Primary color is correct',
run: function () {
if (this.$anchor.css('color') !== "rgb(18, 52, 86)") {
console.error('The primary color should be the one set on the company.');
}
},
}, {
trigger: 'iframe .o_report_layout_standard #informations div strong',
content: 'Secondary color is correct',
run: function () {
if (this.$anchor.css('color') !== "rgb(120, 145, 1)") {
console.error('The secondary color should be the one set on the company.');
}
},
}
]);
});
odoo.define('account.tax.group.tour.tests', function (require) {
"use strict";
var core = require('web.core');
var tour = require('web_tour.tour');
var _t = core._t;
tour.register('account_tax_group', {
test: true,
url: "/web",
}, [tour.stepUtils.showAppsMenuItem(),
{
content: "Go to Invoicing",
trigger: '.o_app[data-menu-xmlid="account.menu_finance"]',
edition: 'community',
},
{
content: "Go to Accounting",
trigger: '.o_app[data-menu-xmlid="account_accountant.menu_accounting"]',
edition: 'enterprise',
},
{
content: "Go to Vendors",
trigger: 'a:contains("Vendors")',
},
{
content: "Go to Bills",
trigger: 'span:contains("Bills")',
},
{
extra_trigger: '.breadcrumb:contains("Bills")',
content: "Create new bill",
trigger: '.o_list_button_add',
},
// Set a vendor
{
content: "Add vendor",
trigger: 'div.o_field_widget.o_field_many2one[name="partner_id"] div input',
run: 'text Azure Interior',
},
{
content: "Valid vendor",
trigger: '.ui-menu-item a:contains("Azure Interior")',
},
// Add First product
{
content: "Add items",
trigger: 'div[name="invoice_line_ids"] .o_field_x2many_list_row_add a:contains("Add a line")',
},
{
content: "Select input",
trigger: 'div[name="invoice_line_ids"] .o_list_view .o_selected_row .o_list_many2one:first input',
},
{
content: "Type item",
trigger: 'div[name="invoice_line_ids"] .o_list_view .o_selected_row .o_list_many2one:first input',
run: "text Large Desk",
},
{
content: "Valid item",
trigger: '.ui-menu-item-wrapper:contains("Large Desk")',
},
// Save account.move
{
content: "Save the account move",
trigger: '.o_form_button_save',
},
// Edit account.move
{
content: "Edit the account move",
trigger: '.o_form_button_edit',
},
// Edit tax group amount
{
content: "Edit tax group amount",
trigger: '.oe_tax_group_amount_value',
},
{
content: "Modify the input value",
trigger: '.tax_group_edit_input input',
run: function (actions) {
$('.tax_group_edit_input input').val(200);
$('.tax_group_edit_input input').select();
var keydownEvent = jQuery.Event('keydown');
keydownEvent.which = 13;
this.$anchor.trigger(keydownEvent);
},
},
// Check new value for total (with modified tax_group_amount).
{
content: "Valid total amount",
trigger: 'span[name="amount_total"]:contains("1,499.00")',
},
// Modify the quantity of the object
{
content: "Select item quantity",
trigger: 'div[name="invoice_line_ids"] .o_list_view tbody tr.o_data_row .o_list_number[title="1.000"]',
},
{
content: "Change item quantity",
trigger: 'div[name="invoice_line_ids"] .o_list_view tbody tr.o_data_row .o_list_number[title="1.000"] input',
run: 'text 2',
},
{
content: "Valid the new value",
trigger: 'div[name="invoice_line_ids"] .o_list_view tbody tr.o_data_row .o_list_number[title="1.000"] input',
run: function (actions) {
var keydownEvent = jQuery.Event('keydown');
keydownEvent.which = 13;
this.$anchor.trigger(keydownEvent);
},
},
// Save form
{
content: "Save the account move",
trigger: '.o_form_button_save',
},
// Check new tax group value
{
content: "Check new value of tax group",
trigger: '.oe_tax_group_amount_value:contains("389.70")',
},
]);
});
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<data>
<record id="idg_road_view_tree" model="ir.ui.view">
<field name="name">idg.road.view.tree</field>
<field name="model">idg.road</field>
<field name="arch" type="xml">
<tree string="Road List" sample="1" create="1" delete="1" multi_edit="0">
<field name="code"/>
<field name="name"/>
</tree>
</field>
</record>
<record id="idg_road_view_form" model="ir.ui.view">
<field name="model">idg.road</field>
<field name="groups_id" eval="[(6, 0, [ref('idg_trayek.group_idg_trayek_admin') ])]"/>
<field name="arch" type="xml">
<form string="Sequences">
<sheet>
<group>
<field name="name" select="1"/>
<field name="code"/>
<field name="active" widget="boolean_toggle"/>
</group>
<notebook>
<page string="Geometry">
<field name="geom" widget="geo_edit_map"/>
</page>
</notebook>
</sheet>
</form>
</field>
</record>
<record id="idg_road_view_search" model="ir.ui.view">
<field name="model">idg.road</field>
<field name="arch" type="xml">
<search string="Sequences">
<field name="name" string="Sequence"/>
<field name="code"/>
<separator/>
<filter string="Archived" name="inactive" domain="[('active', '=', False)]"/>
</search>
</field>
</record>
<!-- <record id="idg_road_form" model="ir.actions.act_window">-->
<!-- <field name="name">Sequences</field>-->
<!-- <field name="type">ir.actions.act_window</field>-->
<!-- <field name="res_model">idg.road</field>-->
<!-- <field name="view_id" ref="idg_road_view_tree"/>-->
<!-- </record>-->
<record id="idg_trayek_road_action" model="ir.actions.act_window">
<field name="name">Road List</field>
<field name="res_model">idg.road</field>
<field name="view_mode">tree,form,geoengine</field>
<field name="view_id" ref="idg_road_view_tree"/>
<field name="help" type="html">
<p class="o_view_nocontent_smiling_face">
Road
</p>
</field>
</record>
<!-- GeoEngine views -->
<record id="idg_road_view0" model="ir.ui.view">
<field name="name">Road view</field>
<field name="arch" type="xml">
<geoengine>
<field name="name" select="1"/>
<field name="code"/>
<field name="active"/>
<field name="geom"/>
</geoengine>
</field>
<field eval="16" name="priority"/>
<field name="model">idg.road</field>
</record>
<record id="idg_road_raster" model="geoengine.raster.layer">
<field name="raster_type">osm</field>
<field name="name">OSM</field>
<field name="view_id" ref="idg_road_view0"/>
<field eval="0" name="overlay"/>
</record>
<record id="idg_road_raster1" model="geoengine.raster.layer">
<field name="raster_type">d_wms</field>
<field name="name">BASIC</field>
<field name="url">vmap0.tiles.osgeo.org/wms/vmap0</field>
<field name="view_id" ref="idg_road_view0"/>
<field eval="1" name="overlay"/>
</record>
</data>
</odoo>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<data>
<record id="idg_trayek_tree" model="ir.ui.view">
<field name="name">idg.trayek.tree</field>
<field name="model">idg.trayek.route</field>
<field name="arch" type="xml">
<tree string="Route List" sample="1" create="1" delete="1" multi_edit="0">
<field name="code" string="Code"/>
<field name="name" string="Name"/>
</tree>
</field>
</record>
<record id="idg_trayek_form" model="ir.ui.view">
<field name="name">idg.trayek.form</field>
<field name="model">idg.trayek.route</field>
<field name="arch" type="xml">
<form string="Letter">
<sheet>
<group>
<div colspan="12">
<h2>
<field name="name" string="Nama Rute" select="1"/>
</h2>
</div>
<field name="code" placeholder="Kode Rute"/>
<field name="active" widget="boolean_toggle"/>
</group>
<notebook>
<page string="Maps">
<field name="geom" widget="geo_edit_map"/>
</page>
<page string="Route Lines" name="route_lines">
<field name="trayek_line"
widget="section_and_note_one2many"
mode="tree">
<tree editable="bottom">
<field name="road_id"/>
</tree>
</field>
</page>
</notebook>
</sheet>
</form>
</field>
</record>
<record id="idg_trayek_route_action" model="ir.actions.act_window">
<field name="name">Route</field>
<field name="res_model">idg.trayek.route</field>
<field name="view_mode">form,tree,geoengine</field>
<field name="view_id" ref="idg_trayek_tree"/>
<field name="help" type="html">
<p class="o_view_nocontent_smiling_face">
Trayek
</p>
</field>
</record>
<!-- GeoEngine views -->
<record id="idg_trayek_geoengine0" model="ir.ui.view">
<field name="name">Trayek view</field>
<field name="model">idg.trayek.route</field>
<field name="arch" type="xml">
<geoengine>
<field name="name"/>
<field name="code"/>
<field name="active"/>
<field name="geom"/>
</geoengine>
</field>
<field eval="16" name="priority"/>
</record>
<record id="idg_trayek_raster" model="geoengine.raster.layer">
<field name="raster_type">osm</field>
<field name="name">OSM</field>
<field name="view_id" ref="idg_trayek_geoengine0"/>
<field eval="0" name="overlay"/>
</record>
<record id="idg_trayek_raster1" model="geoengine.raster.layer">
<field name="raster_type">d_wms</field>
<field name="name">BASIC</field>
<field name="url">vmap0.tiles.osgeo.org/wms/vmap0</field>
<field name="view_id" ref="idg_trayek_geoengine0"/>
<field eval="1" name="overlay"/>
</record>
</data>
</odoo>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<data>
<record id="idg_trayek_vehicle_form" model="ir.ui.view">
<field name="name">idg.trayek.vehicle.form</field>
<field name="model">idg.trayek.vehicle</field>
<field name="arch" type="xml">
<form string="Vehicle">
<sheet>
<group>
<div colspan="12">
<h2>
<field name="name" placeholder="NRKB"/>
</h2>
</div>
<notebook>
<page string="Rincian">
<group>
<field name="partner_id"/>
<field name="vehicle_id"/>
<field name="production_year"/>
<field name="route_id"/>
<field name="permit_no"/>
<field name="permit_due"/>
<field name="active" widget="boolean_toggle"/>
</group>
</page>
</notebook>
</group>
</sheet>
</form>
</field>
</record>
<record id="idg_trayek_vehicle_tree" model="ir.ui.view">
<field name="name">idg.trayek.vehicle.tree</field>
<field name="model">idg.trayek.vehicle</field>
<field name="arch" type="xml">
<tree string="Vehicle List" sample="1" create="1" delete="1" multi_edit="0">
<field name="code"/>
<!-- <field name="name"/>-->
<field name="partner_id"/>
<!-- <field name="vehicle_id"/>-->
<field name="production_year"/>
<field name="route_id"/>
<field name="permit_no"/>
<field name="permit_due"/>
</tree>
</field>
</record>
<record id="idg_trayek_vehicle_search" model="ir.ui.view">
<field name="name">idg.trayek.vehicle.search</field>
<field name="model">idg.trayek.vehicle</field>
<field name="arch" type="xml">
<search string="Name">
<field name="name" string="Owner"/>
<field name="code" string="Code"/>
<separator/>
<filter string="Archived" name="inactive" domain="[('active', '=', False)]"/>
</search>
</field>
</record>
<record id="idg_trayek_vehicle_form_action" model="ir.actions.act_window">
<field name="name">Sequences</field>
<field name="type">ir.actions.act_window</field>
<field name="res_model">idg.trayek.vehicle</field>
<field name="view_id" ref="idg_trayek_vehicle_tree"/>
</record>
<record id="idg_trayek_vehicle_action" model="ir.actions.act_window">
<field name="name">Vehicles</field>
<field name="res_model">idg.trayek.vehicle</field>
<field name="view_mode">kanban,tree,form</field>
<field name="view_id" ref="idg_trayek_vehicle_tree"/>
<field name="help" type="html">
<p class="o_view_nocontent_smiling_face">
Vehicles
</p>
</field>
</record>
</data>
</odoo>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<data>
<record id="idg_vehicle_brand_view_tree" model="ir.ui.view">
<field name="model">idg.vehicle</field>
<field name="arch" type="xml">
<tree string="Vehicle Brand" editable="top" sample="1" create="1" delete="1" multi_edit="0">
<field name="name"/>
</tree>
</field>
</record>
<record id="idg_vehicle_brand_act" model="ir.actions.act_window">
<field name="name">Sequences</field>
<field name="type">ir.actions.act_window</field>
<field name="res_model">idg.vehicle</field>
<field name="view_id" ref="idg_vehicle_brand_view_tree"/>
</record>
<record id="idg_vehicle_brand_action" model="ir.actions.act_window">
<field name="name">Vehicle Brand</field>
<field name="res_model">idg.vehicle</field>
<field name="view_mode">tree</field>
<field name="view_id" ref="idg_vehicle_brand_view_tree"/>
<field name="help" type="html">
<p class="o_view_nocontent_smiling_face">
Vehicle Brand
</p>
</field>
</record>
</data>
</odoo>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<!-- Top menu item -->
<menuitem id="idg_trayek_root_menu"
name="Route Management"
web_icon="idg_trayek,static/description/icon.png"
active="True"
sequence="2"/>
<!-- Transaksi-->
<menuitem id="idg_trayek_vehicle_menu"
name="Kendaraan"
parent="idg_trayek_root_menu"
action="idg_trayek_vehicle_action"
sequence="1"/>
<!-- &lt;!&ndash; Konfigurasi&ndash;&gt;-->
<menuitem id="idg_trayek_config_menu"
name="Configuration"
parent="idg_trayek_root_menu"
sequence="7"/>
<menuitem id="idg_trayek_road_menu"
name="Road"
parent="idg_trayek_config_menu"
action="idg_trayek_road_action"
sequence="1"/>
<menuitem id="idg_trayek_route_menu"
name="Route"
parent="idg_trayek_config_menu"
action="idg_trayek_route_action"
sequence="2"/>
<menuitem id="idg_trayek_owner_menu"
name="Owner"
parent="idg_trayek_config_menu"
action="idg_trayek_partner_action"
sequence="3"/>
<menuitem id="idg_vehicle_brand_menu"
name="Vehicle Brand"
parent="idg_trayek_config_menu"
action="idg_vehicle_brand_action"
sequence="4"/>
</odoo>
<odoo>
<data>
<record id="partner_form_id_trayek" model="ir.ui.view">
<field name="name">partner.form.id.trayek.inherit</field>
<field name="model">res.partner</field>
<field name="inherit_id" ref="id_gov.partner_form_id"/>
<field name="groups_id" eval="[(6, 0, [ref('idg_trayek.group_idg_trayek_admin') ])]"/>
<field name="arch" type="xml">
<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="idg_trayek_partner_action" model="ir.actions.act_window">
<field name="name">Vehicle Owner</field>
<field name="res_model">res.partner</field>
<field name="view_mode">kanban,tree,form</field>
<field name="context">{
'default_is_company': True,
'default_type': 'customer'}
</field>
<field name="help" type="html">
<p class="o_view_nocontent_smiling_face">
Vehicle Owner
</p>
</field>
</record>
</data>
</odoo>
\ No newline at end of file
# Tandur Management
## Fungsi
1. Mengelola data lokasi pertanian
2. Mengelola informasi harga pasar
3. Mengelola rencana tanam dan jadwal panen
## User Type
1. Farmer User
2. Buyer User
3. Investor User
4. Vendor User
5. Tandur Administrator
### Farmer(Vendor dan Customer)
1. Membuat Lokasi Tanah Pertanian/Peternakan
2. Membuat Jadwal Tanam dan Panen
3. Report Analisa Produksi
4. Akses data Investor
5. Akses data Harga Pasar
## Buyer (Customer)
1. Melihat Jadual Panen dan Rencana Produksi
2. Membuat Purchase Order/Production Order
## Investor
1. Melihat Kebutuhan Investasi
2. Membuat syarat dan ketentuan investasi
## Vendor/Seller (e-commerce)
1. Melihat Rencana dan Kebutuhan Farmer
2. Menawarkan Produk kepada Farmer
## Administrator
1. Membuat Farming/BOM Template
2. Product List
# Module
1. Farming Template (BOM)
2. Farming Proses/Production Proses (Manufacturing)
3. Location/Address (Contact)
4. Product
5. Ecommerce
6. Harga Pasar
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from . import controllers
from . import models
from . import wizard
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
{
'name': 'PUBLIC TRANSPORT',
'version': '0.1',
'summary': 'Public Transfor Management',
'sequence': 11,
'description': """
PUBLIC TRANSPORT MANAGEMENT
""",
'category': 'IDG MANAGEMENT',
'website': 'https://opensipkd.com',
'images': [],
'depends': ['base_geoengine', 'id_gov'],
'data': [
'security/account_security.xml',
'security/ir.model.access.csv',
# 'security/ir_rule.xml',
# 'data/sequence.xml',
# 'data/category.xml',
# 'data/type.xml',
'views/idg_trayek_vehicle.xml',
'views/idg_vehicle.xml',
'views/idg_road.xml',
'views/idg_trayek.xml',
'views/partner.xml',
'views/menus.xml',
# 'views/idg_letter_category.xml',
# 'views/idg_letter_type.xml',
# 'views/idg_letter.xml',
# 'views/task_letter.xml',
],
'demo': [
# 'security/ir_rule.xml',
# 'data/res_user.xml',
],
'qweb': [],
'installable': True,
'application': True,
'auto_install': False,
'license': 'LGPL-3',
'module': 'idg_trayek'
}
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from . import onboarding
from . import portal
from odoo import http
from odoo.http import request
class OnboardingController(http.Controller):
@http.route('/pad/pad_invoice_onboarding', auth='user', type='json')
def pad_invoice_onboarding(self):
""" Returns the `banner` for the pad invoice onboarding panel.
It can be empty if the user has closed it or if he doesn't have
the permission to see it. """
company = request.env.company
if not request.env.is_admin() or \
company.pad_invoice_onboarding_state == 'closed':
return {}
return {
'html': request.env.ref('pad.pad_invoice_onboarding_panel')._render({
'company': company,
'state': company.get_and_update_pad_invoice_onboarding_state()
})
}
@http.route('/pad/pad_dashboard_onboarding', auth='user', type='json')
def pad_dashboard_onboarding(self):
""" Returns the `banner` for the pad dashboard onboarding panel.
It can be empty if the user has closed it or if he doesn't have
the permission to see it. """
company = request.env.company
if not request.env.is_admin() or \
company.pad_dashboard_onboarding_state == 'closed':
return {}
return {
'html': request.env.ref('pad.pad_dashboard_onboarding_panel')._render({
'company': company,
'state': company.get_and_update_pad_dashboard_onboarding_state()
})
}
# -*- 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.exceptions import AccessError, MissingError
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 CustomerPortal(CustomerPortal):
def _prepare_home_portal_values(self, counters):
values = super()._prepare_home_portal_values(counters)
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
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))
values = {
'sales': sales,
'resize_to_48': resize_to_48,
}
return self._get_page_view_values(sales, access_token, values,
'my_bphtbs_history', False, **kwargs)
@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()
BphtbSales = request.env['bphtb.sales']
domain = []
if date_begin and date_end:
domain += [('create_date', '>', date_begin), ('create_date', '<=', date_end)]
searchbar_sortings = {
'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 value
if not sortby:
sortby = 'date'
order = searchbar_sortings[sortby]['order']
searchbar_filters = {
'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']
# count for pager
bphtb_count = BphtbSales.search_count(domain)
# make pager
pager = portal_pager(
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
)
# 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,
'saless': saless,
'page_name': 'bphtb',
'pager': pager,
'searchbar_sortings': searchbar_sortings,
'sortby': sortby,
'searchbar_filters': OrderedDict(sorted(searchbar_filters.items())),
'filterby': filterby,
'default_url': '/my/bphtb',
})
return request.render("idg_bphtb.portal_my_bphtb_saless", values)
@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:
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=order_sudo, report_type=report_type,
report_ref='idg_bphtb.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("idg_bphtb.portal_my_bphtb_sales_update_date", values)
return request.render("idg_bphtb.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)
id,code,name,min_omzet,rate,disc,company_id:id,under_value
bphtb_01,01,Jual Beli,60000000,5,0,base.main_company,False
bphtb_02,02,Tukar Menukar,60000000,5,0,base.main_company,False
bphtb_03,03,Hibah,60000000,5,0,base.main_company,False
bphtb_04,04,Hibah Wasiat,300000000,5,50,base.main_company,False
bphtb_05,05,Waris,300000000,5,50,base.main_company,False
bphtb_06,06,Pemasukan dalam Perseroan atau Badan Hukum Lainnya,60000000,5,0,base.main_company,False
bphtb_07,07,Pemisahan Hak yang mengakibatkan Peralihan,60000000,5,0,base.main_company,False
bphtb_08,08,Penunjukan Pembelli dalam Lelang,60000000,5,0,base.main_company,True
bphtb_09,09,Pelaksanaan Putusan Hakim yang mempunyai kekuatan hukum tetap,60000000,5,0,base.main_company,True
bphtb_10,10,Penggabungan Usaha,60000000,5,0,base.main_company,False
bphtb_11,11,Peleburan Usaha,60000000,5,0,base.main_company,False
bphtb_12,12,Pemekaran Usaha,60000000,5,0,base.main_company,False
bphtb_13,13,Hadiah,60000000,5,0,base.main_company,False
bphtb_14,14,Perolehan hak Rumah Sederhana Sehat dan RSS melalui KPR bersubsidi,60000000,5,0,base.main_company,False
bphtb_15,15,Pemberian Hak Baru Kelanjutan Pelepasan Hak,60000000,5,0,base.main_company,False
bphtb_16,16,Pemberian hak baru diluar pelepasan hak,60000000,5,0,base.main_company,False
bphtb_17,17,Tax Amnesti,60000000,5,0,base.main_company,False
bphtb_18,18,Peningkatan Status,0,0,0,base.main_company,False
<?xml version="1.0"?>
<odoo>
<data noupdate="1">
<record id="idg_letter_cat_800" model="idg.letter.category">
<field name='code'>idg_letter_cat_800</field>
<field name='name'>Kepegawaian</field>
<field name="prefix">800/</field>
<field name="suffix">/%(month)s/%(year)s</field>
<field name="padding">4</field>
</record>
<record id="idg_letter_cat_900" model="idg.letter.category">
<field name='code'>idg_letter_cat_900</field>
<field name='name'>KEUANGAN</field>
<field name="prefix">900/</field>
<field name="suffix">/%(month)s/%(year)s</field>
<field name="padding">4</field>
</record>
<record id="idg_letter_cat_920" model="idg.letter.category">
<field name='code'>idg_letter_cat_920</field>
<field name='name'>OTORISASI / SKO</field>
<field name="prefix">920/</field>
<field name="suffix">/%(month)s/%(year)s</field>
<field name="padding">4</field>
</record>
<record id="idg_letter_cat_930" model="idg.letter.category">
<field name='code'>idg_letter_cat_930</field>
<field name='name'>VERIFIKASI</field>
<field name="prefix">930/</field>
<field name="suffix">/%(month)s/%(year)s</field>
<field name="padding">4</field>
</record>
<record id="idg_letter_cat_940" model="idg.letter.category">
<field name='code'>idg_letter_cat_940</field>
<field name='name'>PEMBUKUAN</field>
<field name="prefix">940/</field>
<field name="suffix">/%(month)s/%(year)s</field>
<field name="padding">4</field>
</record>
<record id="idg_letter_cat_950" model="idg.letter.category">
<field name='code'>idg_letter_cat_950</field>
<field name='name'>PERBENDAHARAAN</field>
<field name="prefix">950/</field>
<field name="suffix">/%(month)s/%(year)s</field>
<field name="padding">4</field>
</record>
<record id="idg_letter_cat_960" model="idg.letter.category">
<field name='code'>idg_letter_cat_960</field>
<field name='name'>PEMBINAAN KEBENDAHARAAN</field>
<field name="prefix">960/</field>
<field name="suffix">/%(month)s/%(year)s</field>
<field name="padding">4</field>
</record>
<record id="idg_letter_cat_961" model="idg.letter.category">
<field name='code'>idg_letter_cat_961</field>
<field name='name'>Pemeriksaan Kas Dan Hasil Pemeriksaan Kas</field>
<field name="prefix">961/</field>
<field name="suffix">/%(month)s/%(year)s</field>
<field name="padding">4</field>
</record>
<record id="idg_letter_cat_970" model="idg.letter.category">
<field name='code'>idg_letter_cat_970</field>
<field name='name'>PENDAPATAN</field>
<field name="prefix">940/</field>
<field name="suffix">/%(month)s/%(year)s</field>
<field name="padding">4</field>
</record>
<record id="idg_letter_cat_990" model="idg.letter.category">
<field name='code'>idg_letter_cat_990</field>
<field name='name'>BENDAHARAWAN</field>
<field name="prefix">990/</field>
<field name="suffix">/%(month)s/%(year)s</field>
<field name="padding">4</field>
</record>
</data>
</odoo>
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<data noupdate="1">
<record id="bphtb_partner_admin_kab_id" model="res.partner">
<field name="name">Admin BPHTB Kab/Kota</field>
<field name="street">Jalan-jalan</field>
<field name="country_id" ref="base.id"/>
<field name="state_id" ref="base.state_id_jb"/>
<field name="district_id" ref="id_gov.ct_jb_71"/>
<field name="company_id" ref="base.main_company"/>
<field name="zip">90241</field>
<field name="phone">+62 812-345-678</field>
<field name="email">info@company.idexample.com</field>
<field name="website">www.idexample.com</field>
</record>
<record id="bphtb_user_admin_kab_id" model="res.users">
<field name="login">bphtb_admin</field>
<field name="password">admin</field>
<field name="partner_id" ref="bphtb_partner_admin_kab_id"/>
<field name="company_id" ref="base.main_company"/>
<field name="company_ids" eval="[(4,ref('base.main_company'))]"/>
<field name="groups_id"
eval="[(6,0,[ref('base.group_user'), ref('idg_bphtb.group_bphtb_admin')])]"/>
</record>
<record id="bphtb_partner_ppat_kab_id" model="res.partner">
<field name="name">PPAT Kab/Kota</field>
<field name="street">Jalan-jalan</field>
<field name="country_id" ref="base.id"/>
<field name="state_id" ref="base.state_id_jb"/>
<field name="district_id" ref="id_gov.ct_jb_71"/>
<field name="company_id" ref="base.main_company"/>
<field name="zip">90241</field>
<field name="type">ppat</field>
<field name="phone">+62 812-345-678</field>
<field name="email">info@company.idexample.com</field>
<field name="website">www.idexample.com</field>
</record>
<record id="bphtb_user_ppat_kab_id" model="res.users">
<field name="login">ppat</field>
<field name="password">ppat</field>
<field name="partner_id" ref="bphtb_partner_ppat_kab_id"/>
<field name="company_id" ref="base.main_company"/>
<field name="company_ids" eval="[(4,ref('base.main_company'))]"/>
<field name="groups_id"
eval="[(6,0,[ref('base.group_user'), ref('idg_bphtb.group_bphtb_ppat')])]"/>
</record>
<record id="bphtb_partner_wp_kab_id" model="res.partner">
<field name="name">Wajib Pajak BPHTB</field>
<field name="street">Jalan-jalan</field>
<field name="country_id" ref="base.id"/>
<field name="state_id" ref="base.state_id_jb"/>
<field name="district_id" ref="id_gov.ct_jb_71"/>
<field name="company_id" ref="base.main_company"/>
<field name="zip">90241</field>
<field name="type">wp</field>
<field name="phone">+62 812-345-678</field>
<field name="email">info@company.idexample.com</field>
<field name="website">www.idexample.com</field>
</record>
<record id="bphtb_partner_penjual_kab_id" model="res.partner">
<field name="name">Wajib Pajak Penjual BPHTB</field>
<field name="street">Jalan-jalan</field>
<field name="country_id" ref="base.id"/>
<field name="state_id" ref="base.state_id_jb"/>
<field name="district_id" ref="id_gov.ct_jb_71"/>
<field name="company_id" ref="base.main_company"/>
<field name="zip">90241</field>
<field name="type">wp</field>
<field name="phone">+62 812-345-678</field>
<field name="email">info@company.idexample.com</field>
<field name="website">www.idexample.com</field>
</record>
</data>
</odoo>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<!-- © 2022 Agus Gustiana <aa.gustiana@gmail.com>
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). -->
<odoo>
<data noupdate="1">
<!-- Sequences for Incoming Letter -->
<record id="seq_in_idg_letter" model="ir.sequence">
<field name="name">IDG Incoming Letter</field>
<field name="code">in.idg.letter</field>
<field name="prefix">IN/%(year)s/%(month)s/%(day)s/</field>
<field name="padding">3</field>
</record>
<!-- Sequences for Outgoing Letter -->
<record id="seq_out_idg_letter" model="ir.sequence">
<field name="name">IDG Outgoing Letter</field>
<field name="code">out.idg.letter</field>
<field name="prefix">OUT/%(year)s/%(month)s/%(day)s/</field>
<field name="padding">3</field>
</record>
</data>
</odoo>
<?xml version="1.0"?>
<odoo>
<data noupdate="0">
<record id="idg_letter_01" model="idg.letter.type">
<field name='code'>01</field>
<field name='name'>Peraturan</field>
<field name='active'>1</field>
</record>
<record id="idg_letter_02" model="idg.letter.type">
<field name='code'>02</field>
<field name='name'>Pedoman</field>
<field name='active'>1</field>
</record>
<record id="idg_letter_03" model="idg.letter.type">
<field name='code'>03</field>
<field name='name'>Petunjuk Pelaksanaan</field>
<field name='active'>1</field>
</record>
<record id="idg_letter_04" model="idg.letter.type">
<field name='code'>04</field>
<field name='name'>Standar Operasional dan Prosedur</field>
<field name='active'>1</field>
</record>
<record id="idg_letter_05" model="idg.letter.type">
<field name='code'>05</field>
<field name='name'>Keputusan</field>
<field name='active'>1</field>
</record>
<record id="idg_letter_06" model="idg.letter.type">
<field name='code'>06</field>
<field name='name'>Instruksi</field>
<field name='active'>1</field>
</record>
<record id="idg_letter_07" model="idg.letter.type">
<field name='code'>07</field>
<field name='name'>Surat Perintah</field>
<field name='active'>1</field>
</record>
<record id="idg_letter_08" model="idg.letter.type">
<field name='code'>08</field>
<field name='name'>Surat Tugas</field>
<field name='active'>1</field>
</record>
<record id="idg_letter_09" model="idg.letter.type">
<field name='code'>09</field>
<field name='name'>Nota Dinas</field>
<field name='active'>1</field>
</record>
<record id="idg_letter_10" model="idg.letter.type">
<field name='code'>10</field>
<field name='name'>Memorandum</field>
<field name='active'>1</field>
</record>
<record id="idg_letter_11" model="idg.letter.type">
<field name='code'>11</field>
<field name='name'>Surat Dinas</field>
<field name='active'>1</field>
</record>
<record id="idg_letter_12" model="idg.letter.type">
<field name='code'>12</field>
<field name='name'>Surat Undangan</field>
<field name='active'>1</field>
</record>
<record id="idg_letter_13" model="idg.letter.type">
<field name='code'>13</field>
<field name='name'>Surat Perjanjian</field>
<field name='active'>1</field>
</record>
<record id="idg_letter_14" model="idg.letter.type">
<field name='code'>14</field>
<field name='name'>Surat Kuasa</field>
<field name='active'>1</field>
</record>
<record id="idg_letter_15" model="idg.letter.type">
<field name='code'>15</field>
<field name='name'>Berita Acara</field>
<field name='active'>1</field>
</record>
<record id="idg_letter_16" model="idg.letter.type">
<field name='code'>16</field>
<field name='name'>Surat Keterangan</field>
<field name='active'>1</field>
</record>
<record id="idg_letter_17" model="idg.letter.type">
<field name='code'>17</field>
<field name='name'>Surat Pengantar</field>
<field name='active'>1</field>
</record>
<record id="idg_letter_18" model="idg.letter.type">
<field name='code'>18</field>
<field name='name'>Pengumuman</field>
<field name='active'>1</field>
</record>
<record id="idg_letter_19" model="idg.letter.type">
<field name='code'>19</field>
<field name='name'>Laporan</field>
<field name='active'>1</field>
</record>
<record id="idg_letter_20" model="idg.letter.type">
<field name='code'>20</field>
<field name='name'>Telaahan Staff</field>
<field name='active'>1</field>
</record>
</data>
</odoo>
id,ppat_id:id,wp_id:id,seller_id:id,state,nop,tax_year,luas_bumi,luas_bng,njop_bumi,njop_bng,luas_bumi_bersama,luas_bng_bersama,njop_bumi_bersama,njop_bng_bersama,jenis_id:id,rate,min_omzet,disc_sk,npop,basic,fine,amount,disc_amount,owed,typ,company_id:id,certicate_no
sspd_01,bphtb_partner_ppat_kab_id,bphtb_partner_wp_kab_id,bphtb_partner_penjual_kab_id,draft,367601000100100010,2021,100,50,500000000,250000000,0,0,00,0,bphtb_01,5,60000000,,1000000000,0,0,0,0,0,sspd,base.main_company,-
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<data noupdate="1">
<record id="pdl_partner_company_id" model="res.partner">
<field name="name">Kabupaten/Kota</field>
<field name="street">Jalan-jalan</field>
<field name="country_id" ref="base.id"/>
<field name="state_id" ref="base.state_id_jb"/>
<field name="district_id" ref="id_gov.ct_jb_71"/>
<field name="zip">90241</field>
<field name="phone">+62 812-345-678</field>
<field name="email">info@company.idexample.com</field>
<field name="website">www.idexample.com</field>
</record>
<record id="pdl_company_id" model="res.company">
<field name="name">Kabupaten/Kota Company</field>
<field name="partner_id" ref="pdl_partner_company_id"/>
</record>
</data>
<data>
<function model="res.users" name="write">
<value eval="[ref('base.user_root'), ref('base.user_admin'), ref('base.user_demo')]"/>
<value eval="{'company_ids': [(4, ref('pdl_kab.pdl_company_id'))]}"/>
</function>
</data>
</odoo>
\ No newline at end of file
File mode changed
from . import idg_road
from . import idg_trayek
import logging
from datetime import datetime, timedelta
import pytz
from odoo import models, api, fields, _
# from odoo.addons.base.models.ir_sequence import (_create_sequence, _drop_sequences, _alter_sequence, _select_nextval,
# _update_nogap)
# from odoo.tools import sql
from odoo.exceptions import UserError
from psycopg2 import sql
_logger = logging.getLogger(__name__)
class IdgRoad(models.Model):
_name = 'idg.road'
_description = 'Public Road Management'
_order = "name"
name = fields.Char(required=True)
code = fields.Char(string='Code')
length = fields.Float(string='Length')
active = fields.Boolean(default=True, string="Active")
geom = fields.GeoLine(srid=4326)
from datetime import datetime, timedelta
from odoo import api, fields, models, _
import logging
import re
_logger = logging.getLogger(__name__)
class IdgTrayek(models.Model):
_name = 'idg.trayek.route'
_description = 'Public Route'
# _inherit = ['mail.thread', 'mail.activity.mixin']
# _sequence_field = "code"
# _sequence_date_field = "date"
code = fields.Char(index=True, string='Code')
name = fields.Char(index=True, string='Name', size=255, required=True)
active = fields.Boolean(default=True, string='Active')
# geom = field.Geom()
trayek_line = fields.One2many('idg.trayek.route.line', 'trayek_id',
string='Trayek Lines',
copy=True, auto_join=True)
geom = fields.GeoLine(srid=4326)
class IdgTrayekLine(models.Model):
_name = 'idg.trayek.route.line'
_description = 'Public Route Line'
# _inherit = ['mail.thread', 'mail.activity.mixin', ]
trayek_id = fields.Many2one('idg.trayek.route')
road_id = fields.Many2one('idg.road')
class IdgVehicle(models.Model):
_name = 'idg.vehicle'
_description = 'Vehicle Merek'
# _inherit = ['mail.thread', 'mail.activity.mixin']
# _sequence_field = "code"
# _sequence_date_field = "date"
# code = fields.Char(index=True, string='Code')
name = fields.Char(index=True, string='Name', size=255, required=True)
class IdgTrayekVehicle(models.Model):
_name = 'idg.trayek.vehicle'
_description = 'Public Transport Route'
# _inherit = ['mail.thread', 'mail.activity.mixin', ]
code = fields.Char(index=True, string='Code', compute='_compute_code',
store=True, copy=False, tracking=True)
name = fields.Char(string='Name', index=True)
partner_id = fields.Many2one('res.partner')
vehicle_id = fields.Many2one('idg.vehicle')
route_id = fields.Many2one('idg.trayek.route')
permit_no = fields.Char(index=True, string='Permit')
permit_due = fields.Date(string='Due Date')
production_year = fields.Char(size=4, string='Production Year')
active = fields.Boolean(default=True, string='Active')
@api.depends('name')
def _compute_code(self):
for rec in self:
rec_str = re.sub('[0-9]', " ", rec.name).split()
if len(rec_str) == 1:
rec_str.append(" ")
rec_num = re.sub("[a-zA-Z]", " ", rec.name)
rec.code = f"{rec_str[0].ljust(2)}{rec_str[1].ljust(3)}{rec_num.strip()}"
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<data noupdate="0">
<record model="ir.module.category" id="idg_trayek">
<field name="name">Trayek Management</field>
<field name="description">Trayek Management</field>
<field name="sequence">12</field>
</record>
<record id="group_idg_trayek_user" model="res.groups">
<field name="name">User</field>
<field name="category_id" ref="idg_trayek"/>
</record>
<record id="group_idg_trayek_admin" model="res.groups">
<field name="name">Administrator</field>
<field name="category_id" ref="idg_trayek"/>
<field name="implied_ids" eval="[(4, ref('group_idg_trayek_user'))]"/>
<field name="users" eval="[(4, ref('base.user_root')), (4, ref('base.user_admin'))]"/>
</record>
</data>
</odoo>
"id","name","model_id:id","group_id:id","perm_read","perm_write","perm_create","perm_unlink"
"access_idg_letter_category_user","access.idg.letter.category.user","model_idg_letter_category","base.group_user",1,0,0,0
"access_idg_letter_user","access.idg.letter.user","model_idg_letter","base.group_user",1,1,1,1
"access_idg_letter_routes_user","access.idg.letter.routes.user","model_idg_letter_routes","base.group_user",1,0,1,0
"access_idg_letter_comments_user","access.idg.letter.comments.user","model_idg_letter_routes","base.group_user",1,0,1,0
"access_idg_letter_docs_user","access.idg.letter.docs.user","model_idg_letter_comments","base.group_user",1,0,1,0
"access_idg_letter_comments_admin","access.idg.letter.comments.admin","model_idg_letter_comments","group_idg_letter_admin",1,1,1,1
"access_idg_letter_docs_admin","access.idg.letter.docs.admin","model_idg_letter_docs","group_idg_letter_admin",1,1,1,1
"access_idg_letter_category_admin","access.idg.letter.category.admin","model_idg_letter_category","group_idg_letter_admin",1,1,1,1
"access_idg_letter_category_user","access.idg.letter.category.user","model_idg_letter_category","group_idg_letter_user",1,1,1,1
"access_idg_letter_category_base","access.idg.letter.category.base","model_idg_letter_category","base.group_user",1,0,0,0
"access_idg_letter_category_approver_base","access.idg.letter.category.approver.base","model_idg_letter_category_approver","base.group_user",1,0,0,0
"access_idg_letter_category_approver_admin","access.idg.letter.category.approver.admin","model_idg_letter_category_approver","group_idg_letter_admin",1,1,1,1
"access_idg_letter_admin","access.idg.letter.admin","model_idg_letter","group_idg_letter_admin",1,1,1,1
"access_idg_letter_approver_admin","access.idg.letter.approver.admin","model_idg_letter_approver","group_idg_letter_admin",1,1,1,1
\ No newline at end of file
"id","name","model_id:id","group_id:id","perm_read","perm_write","perm_create","perm_unlink"
"access_idg_road","access.idg.road","model_idg_road","base.group_user",1,0,0,0
"access_idg_road_user","access.idg.road.user","model_idg_road","group_idg_trayek_user",1,1,1,0
"access_idg_road_admin","access.idg.road.admin","model_idg_road","group_idg_trayek_admin",1,1,1,1
"access_idg_trayek_route","access.idg.trayek.route","model_idg_trayek_route","base.group_user",1,0,0,0
"access_idg_trayek_route_user","access.idg.trayek.route.user","model_idg_trayek_route","group_idg_trayek_user",1,1,1,0
"access_idg_trayek_route_admin","access.idg.trayek.route.admin","model_idg_trayek_route","group_idg_trayek_admin",1,1,1,1
"access_idg_trayek_route_line","access.idg.trayek.route.line","model_idg_trayek_route_line","base.group_user",1,0,0,0
"access_idg_trayek_route_line_user","access.idg.trayek.route.line.user","model_idg_trayek_route_line","group_idg_trayek_user",1,1,1,0
"access_idg_trayek_route_line_admin","access.idg.trayek.route.line.admin","model_idg_trayek_route_line","group_idg_trayek_admin",1,1,1,1
"access_idg_vehicle","access.idg.vehicle","model_idg_vehicle","base.group_user",1,0,0,0
"access_idg_vehicle_user","access.idg.vehicle.user","model_idg_vehicle","group_idg_trayek_user",1,1,1,0
"access_idg_vehicle_admin","access.idg.vehicle.admin","model_idg_vehicle","group_idg_trayek_admin",1,1,1,1
"access_idg_trayek_vehicle","access.idg.trayek.vehicle","model_idg_trayek_vehicle","base.group_user",1,0,0,0
"access_idg_trayek_vehicle_user","access.idg.trayek.vehicle.user","model_idg_trayek_vehicle","group_idg_trayek_user",1,1,1,0
"access_idg_trayek_vehicle_admin","access.idg.trayek.vehicle.admin","model_idg_trayek_vehicle","group_idg_trayek_admin",1,1,1,1
<?xml version="1.0"?>
<odoo>
<data noupdate="0">
<record model="ir.rule" id="idg_letter_owner_rule">
<field name="name">IDG Letter Owner Rule</field>
<field name="model_id" ref="model_idg_letter"/>
<field name="groups" eval="[4,ref('base.group_user')]"/>
<field name="domain_force">[('create_uid', '=', user.id)]</field>
<field name="perm_read" eval="True"/>
<field name="perm_create" eval="True"/>
<field name="perm_write" eval="True"/>
<field name="perm_unlink" eval="False"/>
</record>
<record model="ir.rule" id="idg_letter_owner_delete_rule">
<field name="name">IDG Letter Owner Delete Rule</field>
<field name="model_id" ref="model_idg_letter"/>
<field name="groups" eval="[4,ref('base.group_user')]"/>
<field name="domain_force">[('create_uid', '=', user.id), ('state','=','canceled')]</field>
<field name="perm_read" eval="False"/>
<field name="perm_create" eval="False"/>
<field name="perm_write" eval="False"/>
<field name="perm_unlink" eval="True"/>
</record>
<record model="ir.rule" id="idg_letter_write_rule">
<field name="name">IDG Letter Write Rule</field>
<field name="model_id" ref="model_idg_letter"/>
<field name="groups" eval="[4,ref('base.group_user')]"/>
<!-- <field name="domain_force">[('approvers.create_uid', '=', user.id), ('state','in',['draft','new'])]</field>-->
<field name="perm_read" eval="False"/>
<field name="perm_create" eval="False"/>
<field name="perm_write" eval="True"/>
<field name="perm_unlink" eval="False"/>
</record>
<record model="ir.rule" id="idg_letter_approver_read_rule">
<field name="name">IDG Letter Approver Rule</field>
<field name="model_id" ref="model_idg_letter"/>
<field name="groups" eval="[4,ref('base.group_user')]"/>
<field name="domain_force">[('approver_ids.user_id.id', '=', user.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="idg_letter_approver_write_rule">
<field name="name">IDG Letter Approver Write Rule</field>
<field name="model_id" ref="model_idg_letter_approver"/>
<field name="groups" eval="[4,ref('base.group_user')]"/>
<field name="domain_force">[('required', '=', True)]</field>
<field name="perm_read" eval="True"/>
<field name="perm_create" eval="True"/>
<field name="perm_write" eval="True"/>
<field name="perm_unlink" eval="False"/>
</record>
<record model="ir.rule" id="idg_letter_approver_delete_rule">
<field name="name">IDG Letter Approver Delete Rule</field>
<field name="model_id" ref="model_idg_letter_approver"/>
<field name="groups" eval="[4,ref('base.group_user')]"/>
<field name="domain_force">[('required', '=', False)]</field>
<field name="perm_read" eval="True"/>
<field name="perm_create" eval="True"/>
<field name="perm_write" eval="True"/>
<field name="perm_unlink" eval="True"/>
</record>
<record model="ir.rule" id="idg_letter_admin_rule">
<field name="name">IDG Letter Admin Rule</field>
<field name="model_id" ref="model_idg_letter"/>
<field name="groups" eval="[4,ref('group_idg_letter_admin')]"/>
<field name="perm_read" eval="True"/>
<field name="perm_create" eval="True"/>
<field name="perm_write" eval="True"/>
<field name="perm_unlink" eval="True"/>
</record>
<record model="ir.rule" id="idg_letter_category_admin_rule">
<field name="name">IDG Letter Category Admin Rule</field>
<field name="model_id" ref="model_idg_letter_category"/>
<field name="groups" eval="[4,ref('group_idg_letter_admin')]"/>
<field name="perm_read" eval="True"/>
<field name="perm_create" eval="True"/>
<field name="perm_write" eval="True"/>
<field name="perm_unlink" eval="True"/>
</record>
<record model="ir.rule" id="idg_letter_category_user_rule">
<field name="name">IDG Letter Category User Rule</field>
<field name="model_id" ref="model_idg_letter_category"/>
<field name="groups" eval="[4,ref('group_idg_letter_user')]"/>
<field name="perm_read" eval="True"/>
<field name="perm_create" eval="True"/>
<field name="perm_write" eval="True"/>
<field name="perm_unlink" eval="False"/>
</record>
<record model="ir.rule" id="idg_letter_category_rule">
<field name="name">IDG Letter Category Rule</field>
<field name="model_id" ref="model_idg_letter_category"/>
<field name="groups" eval="[4,ref('base.group_user')]"/>
<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="idg_letter_category_approver_admin_rule">
<field name="name">IDG Letter Category Approver Admin Rule</field>
<field name="model_id" ref="model_idg_letter_category_approver"/>
<field name="groups" eval="[4,ref('group_idg_letter_admin')]"/>
<field name="perm_read" eval="True"/>
<field name="perm_create" eval="True"/>
<field name="perm_write" eval="True"/>
<field name="perm_unlink" eval="True"/>
</record>
<record model="ir.rule" id="idg_letter_category_approver_user_rule">
<field name="name">IDG Letter Category Approver User Rule</field>
<field name="model_id" ref="model_idg_letter_category_approver"/>
<field name="groups" eval="[4,ref('group_idg_letter_user')]"/>
<field name="perm_read" eval="True"/>
<field name="perm_create" eval="True"/>
<field name="perm_write" eval="True"/>
<field name="perm_unlink" eval="False"/>
</record>
<record model="ir.rule" id="idg_letter_category_approver_rule">
<field name="name">IDG Letter Category Approves Rule</field>
<field name="model_id" ref="model_idg_letter_category_approver"/>
<field name="groups" eval="[4,ref('base.group_user')]"/>
<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>
</data>
</odoo>
\ No newline at end of file
Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!