Commit 32052b99 by aa.gusti

village

1 parent d1b50cc4
......@@ -4,65 +4,60 @@ Odoo Accounting
The Odoo <a href="https://www.odoo.com/page/accounting">Open Source Accounting</a> app allows a better way to
collaborate with your accountants, your customers and control your suppliers.
Activate features on demand, from integrated analytic accounting to budget,
assets and multiple companies consolidation.
Activate features on demand, from integrated analytic accounting to budget, assets and multiple companies consolidation.
A Smart User Interface
----------------------
Record transactions in a few clicks and easily manage all financial activities
in one place. Odoo's user interface is designed with productivity in mind.
Record transactions in a few clicks and easily manage all financial activities in one place. Odoo's user interface is
designed with productivity in mind.
A Better Way To Work – Together
-------------------------------
Share access to your latest business numbers with your team and your accountant
– so everyone is up to speed. From work, home or on the go.
Share access to your latest business numbers with your team and your accountant – so everyone is up to speed. From work,
home or on the go.
Connect Your Bank Accounts
--------------------------
Import your bank statements and reconcile them in just a few clicks. Prepare
payment orders based on your supplier invoices and payment terms.
Import your bank statements and reconcile them in just a few clicks. Prepare payment orders based on your supplier
invoices and payment terms.
Electronic invoicing and automated follow-ups
---------------------------------------------
Create and send professional invoices & get paid online. Get rid of the stress
of having to constantly remind your debtors. Simply set-up and automate
follow-ups to get paid quickly.
Create and send professional invoices & get paid online. Get rid of the stress of having to constantly remind your
debtors. Simply set-up and automate follow-ups to get paid quickly.
Sales Integration
-----------------
Automatically create invoices from sales orders, delivery orders or base them
on time and material. Re-invoice expenses on projects to your customer in just
a few clicks.
Automatically create invoices from sales orders, delivery orders or base them on time and material. Re-invoice expenses
on projects to your customer in just a few clicks.
Purchase Integration
--------------------
Control supplier invocies based on purchase orders. Get real-time inventory
valuation reports automatically posted in your accounts.
Control supplier invocies based on purchase orders. Get real-time inventory valuation reports automatically posted in
your accounts.
Multi-Level Analytic Accounting
-------------------------------
Integrate your analytic accounting operations with timesheets, projects,
invoices, expenses, etc. No need to record transactions, all analytic entries
are posted automatically following your business rules.
Integrate your analytic accounting operations with timesheets, projects, invoices, expenses, etc. No need to record
transactions, all analytic entries are posted automatically following your business rules.
Everything you need to grow
---------------------------
Manage your assets, track expenses, control budgets, multi-level analytic
accounting; Odoo has all the features you need to sustain all your business
activities.
Manage your assets, track expenses, control budgets, multi-level analytic accounting; Odoo has all the features you need
to sustain all your business activities.
Scale With Your Organization
----------------------------
Odoo supports multiple currencies, multiple users with different access rights,
multiple companies with real time consolidation and unlimited analytic plans.
Odoo supports multiple currencies, multiple users with different access rights, multiple companies with real time
consolidation and unlimited analytic plans.
......@@ -23,8 +23,8 @@ Menydiakan module untuk followup Wajib Pajak/Retribusi.
'views/view_config.xml',
'views/objek_pajak.xml',
'views/district.xml',
# 'views/sub_district.xml',
# 'views/village.xml',
'views/sub_district.xml',
'views/village.xml',
'views/sudut_pandang.xml',
'views/pdl_kab_menus.xml',
'security/account_security.xml',
......
......@@ -30,7 +30,8 @@ class PortalAccount(CustomerPortal):
return self._get_page_view_values(invoice, access_token, values, 'my_pad_history', False, **kwargs)
def _get_pad_domain(self):
return [('move_type', 'in', ('out_invoice', 'out_refund', 'in_invoice', 'in_refund', 'out_receipt', 'in_receipt'))]
return [
('move_type', 'in', ('out_invoice', 'out_refund', 'in_invoice', 'in_refund', 'out_receipt', 'in_receipt'))]
@http.route(['/my/pad', '/my/pad/page/<int:page>'], type='http', auth="user", website=True)
def portal_my_pad(self, page=1, date_begin=None, date_end=None, sortby=None, filterby=None, **kw):
......@@ -86,7 +87,7 @@ class PortalAccount(CustomerPortal):
'searchbar_sortings': searchbar_sortings,
'sortby': sortby,
'searchbar_filters': OrderedDict(sorted(searchbar_filters.items())),
'filterby':filterby,
'filterby': filterby,
})
return request.render("account.portal_my_pad", values)
......@@ -98,13 +99,15 @@ class PortalAccount(CustomerPortal):
return request.redirect('/my')
if report_type in ('html', 'pdf', 'text'):
return self._show_report(model=invoice_sudo, report_type=report_type, report_ref='account.account_pad', download=download)
return self._show_report(model=invoice_sudo, report_type=report_type, report_ref='account.account_pad',
download=download)
values = self._invoice_get_page_view_values(invoice_sudo, access_token, **kw)
acquirers = values.get('acquirers')
if acquirers:
country_id = values.get('partner_id') and values.get('partner_id')[0].country_id.id
values['acq_extra_fees'] = acquirers.get_acquirer_extra_fees(invoice_sudo.amount_residual, invoice_sudo.currency_id, country_id)
values['acq_extra_fees'] = acquirers.get_acquirer_extra_fees(invoice_sudo.amount_residual,
invoice_sudo.currency_id, country_id)
return request.render("account.portal_invoice_page", values)
......@@ -119,11 +122,16 @@ class PortalAccount(CustomerPortal):
if not partner.can_edit_vat():
if 'vat' in data and (data['vat'] or False) != (partner.vat or False):
error['vat'] = 'error'
error_message.append(_('Changing VAT number is not allowed once pad have been issued for your account. Please contact us directly for this operation.'))
error_message.append(
_('Changing VAT number is not allowed once pad have been issued for your account. Please contact '
'us directly for this operation.'))
if 'name' in data and (data['name'] or False) != (partner.name or False):
error['name'] = 'error'
error_message.append(_('Changing your name is not allowed once pad have been issued for your account. Please contact us directly for this operation.'))
error_message.append(
_('Changing your name is not allowed once pad have been issued for your account. Please contact '
'us directly for this operation.'))
if 'company_name' in data and (data['company_name'] or False) != (partner.company_name or False):
error['company_name'] = 'error'
error_message.append(_('Changing your company name is not allowed once pad have been issued for your account. Please contact us directly for this operation.'))
error_message.append(
_('Changing your company name is not allowed once pad have been issued for your account. Please contact us directly for this operation.'))
return error, error_message
......@@ -8,11 +8,19 @@ class District(models.Model):
_name = 'res.district'
_description = 'Kota/Kabupaten'
state_id = fields.Many2one('res.country.state', string='Provinsi', required=True)
typ = fields.Selection([
('kab', 'Kabupaten'),
('kabtif', 'Kabupaten Administratif'),
('kota', 'Kota'),
('kotif', 'Kota Administratif')],
string='Jenis')
code = fields.Char(string="Kode Kota/Kabupaten")
name = fields.Char(string="Nama Kota/Kabupaten", index=True)
display_code = fields.Char(index=True)
# display_code = fields.Char(compute='_compute_display_code', store=True, index=True)
# sub_district_ids = fields.One2many('res.district.sub', 'district_id', string='Kecamatan')
# display_code = fields.Char(compute='_compute_display_code') #, store=True, index=True)
display_name = fields.Char(index=True)
# display_name = fields.Char(compute='_compute_display_name') #, store=True, index=True)
sub_district_ids = fields.One2many('res.district.sub', 'district_id', string='Kecamatan')
# address_view_id = fields.Many2one(
# comodel_name='ir.ui.view', string="Input View",
# domain=[('model', '=', 'res.partner'), ('type', '=', 'form')],
......@@ -25,49 +33,55 @@ class District(models.Model):
# compute="_compute_image_url", string="Flag",
# help="Url of static flag image",
# )
_sql_constraints = [
('code_uniq', 'unique (state_id,code)', 'Kode Kabupaten/Kota Harus Unik !'),
('name_uniq', 'unique (state_id,typ,name)', 'Nama Kabupaten/Kota Harus Unik !'),
]
@api.model
def _name_search(self, name, args=None, operator='ilike', limit=100, name_get_uid=None):
args = args or []
if self.env.context.get('state_id'):
args = expression.AND([args, [('state_id', '=', self.env.context.get('state_id'))]])
if operator == 'ilike' and not (name or '').strip():
first_domain = []
domain = []
else:
first_domain = [('code', '=ilike', name)]
domain = [('name', operator, name)]
first_district_ids = self._search(expression.AND([first_domain, args]), limit=limit,
access_rights_uid=name_get_uid) if first_domain else []
return list(first_district_ids) + [
state_id
for state_id in self._search(expression.AND([domain, args]),
limit=limit, access_rights_uid=name_get_uid)
if state_id not in first_district_ids
]
def name_get(self):
result = []
for record in self:
result.append((record.id, "{} {} ({})".format(record.typ, record.name, record.state_id.code)))
return result
def code_get(self):
result = []
for record in self:
result.append((record.id, "{}.{}".format(record.state_id.code, record.code)))
return result
@api.depends('name')
def _compute_display_name(self):
pass
# self.display_name = "{} {}".format(self.typ, self.name)
@api.depends('code')
def _compute_display_code(self):
pass
# self.display_code = "{}.{}".format(self.state_id.code, self.code)
# @api.model
# def _name_search(self, name, args=None, operator='ilike', limit=100, name_get_uid=None):
# args = args or []
# if self.env.context.get('state_id'):
# args = expression.AND([args, [('state_id', '=', self.env.context.get('state_id'))]])
#
# if operator == 'ilike' and not (name or '').strip():
# first_domain = []
# domain = []
# else:
# first_domain = [('code', '=ilike', name)]
# domain = [('name', operator, name)]
#
# first_district_ids = self._search(expression.AND([first_domain, args]), limit=limit,
# access_rights_uid=name_get_uid) if first_domain else []
# return list(first_district_ids) + [
# state_id
# for state_id in self._search(expression.AND([domain, args]),
# limit=limit, access_rights_uid=name_get_uid)
# if state_id not in first_district_ids
# ]
#
# def name_get(self):
# result = []
# for record in self:
# result.append((record.id, "{} ({})".format(record.name, record.state_id.code)))
# return result
#
# def code_get(self):
# result = []
# for record in self:
# result.append((record.id, "{} ({})".format(record.state_id.code, record.code)))
# return result
#
# @api.depends('code')
# def _compute_display_code(self):
# return self.code_get()
# # result = []
# # for record in self:
# # result.append((record.id, "{} ({})".format(record.state_id.code, record.code)))
# # return result
#
# @api.model_create_multi
# def create(self, vals_list):
# for vals in vals_list:
......@@ -112,11 +126,15 @@ class Village(models.Model):
_name = 'res.district.village'
_description = "Desa/Keurahan"
sub_district_id = fields.Many2one('res.district.sub', string='Kecamatan', required=True)
typ = fields.Selection([
('desa', 'Desa'),
('kelurahan', 'Kelurahan')],
string='Jenis')
code = fields.Char(string="Kode Desa/Kelurahan")
name = fields.Char(string="Nama Desa/Kelurahan", index=True)
display_code = fields.Char(index=True) # compute='_compute_display_code', store=True,
display_name = fields.Char(index=True) # compute='_compute_display_name', store=True,
_sql_constraints = [
('village_code_uniq', 'unique (sub_district_id,code)', 'Kode Kelurahan/Desa Harus Unik !'),
('village_name_uniq', 'unique (sub_district_id,name)', 'Nama Kelurahan/Desa Harus Unik !'),
('village_name_uniq', 'unique (sub_district_id,typ,name)', 'Nama Kelurahan/Desa Harus Unik !'),
]
import time
import logging
from psycopg2 import sql, DatabaseError
from odoo import api, fields, models, _
from odoo import fields, models
class PdlSudutPandang(models.Model):
_name = 'pdl.sudut.pandang'
_description = 'Sudut Pandang'
code = fields.Char(String='Kode', width=32)
name = fields.Char(index=True, String='Nama', width=64)
value = fields.Float(String='Nilai')
code = fields.Char(string='Kode', size=32)
name = fields.Char(index=True, string='Nama', size=64)
value = fields.Float(string='Nilai')
_sql_constraints = [
('code_uniq', 'unique (code)', 'Kode harus unik')
......
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<data noupdate="0">
<record model="ir.module.category" id="pdl_kab">
<field name="name">PDL</field>
<field name="description">PDL</field>
......
"id","name","model_id:id","group_id:id","perm_read","perm_write","perm_create","perm_unlink"
"access_sudut_pandang_config","access.sudut.pandang.config","model_pdl_sudut_pandang","base.group_system",1,1,1,1
"access_sudut_pandang_config_pdl_admin","access.sudut.pandang.config.pdl.admin","model_pdl_sudut_pandang","group_pdl_konfigurasi",1,1,1,1
"access_sudut_pandang_admin","access.sudut.pandang.admin","model_pdl_sudut_pandang","base.group_system",1,1,1,1
"access_sudut_pandang_admin_pdl","access.sudut.pandang.admin.pdl","model_pdl_sudut_pandang","group_pdl_konfigurasi",1,1,1,1
"access_district_admin","access.district.admin","model_res_district","base.group_system",1,1,1,1
"access_district_admin_pdl","access.district.admin.pdl","model_res_district","group_pdl_konfigurasi",1,1,1,1
"access_district_sub_admin","access.district.sub.admin","model_res_district_sub","base.group_system",1,1,1,1
"access_district_sub_admin_pdl","access.district.sub.admin.pdl","model_res_district_sub","group_pdl_konfigurasi",1,1,1,1
"access_village_admin","access.village.admin","model_res_district_village","base.group_system",1,1,1,1
"access_village_admin_pdl","access.village.admin.pdl","model_res_district_village","group_pdl_konfigurasi",1,1,1,1
.openerp div.oe_account_help {
background : #D6EBFF;
background: #D6EBFF;
width: 100%;
padding: 10px;
border: 3px solid #C1D4E6;
}
.openerp p.oe_account_font_help{
.openerp p.oe_account_font_help {
text-align: left;
font-weight: bold;
margin: 0px;
font-size: 14px;
}
.openerp p.oe_account_font_content{
.openerp p.oe_account_font_content {
margin-left: 30px;
font-size: 14px;
}
.openerp p.oe_account_font_title{
.openerp p.oe_account_font_title {
margin-top: 7px;
font-size: 15px;
font-style: italic;
......
.openerp .oe_force_bold {
font-weight: bold !important;
font-weight: bold !important;
}
.openerp label.oe_open_balance{
.openerp label.oe_open_balance {
margin-right: -18px;
}
.openerp label.oe_subtotal_footer_separator{
float:right;
.openerp label.oe_subtotal_footer_separator {
float: right;
width: 184px !important;
}
.openerp label.oe_mini_subtotal_footer_separator{
.openerp label.oe_mini_subtotal_footer_separator {
margin-right: -14px;
}
.openerp .oe_account_total, .openerp .oe_pos_total {
margin-left: -2px;
}
.openerp label.oe_real_closing_balance{
.openerp label.oe_real_closing_balance {
min-width: 184px !important;
}
.openerp label.oe_difference, .openerp label.oe_pos_difference {
margin-right: -10px;
padding-left: 10px !important;
min-width: 195px !important;
}
.openerp .oe_opening_total{
margin-right: 4px;
.openerp .oe_opening_total {
margin-right: 4px;
}
.o_payment_label{
padding-right: 20px;
.o_payment_label {
padding-right: 20px;
}
\ No newline at end of file
......@@ -12,14 +12,14 @@
}
.oe_tax_group_name {
font-weight: bold;
font-weight: bold;
min-width: 150px;
text-align: right;
padding-right: 20px;
}
.oe_tax_group_editable .oe_tax_group_amount_value input {
width: 65%;
float: right;
width: 65%;
float: right;
text-align: right;
}
odoo.define('account.AccountPortalSidebar', function (require) {
'use strict';
'use strict';
const dom = require('web.dom');
var publicWidget = require('web.public.widget');
var PortalSidebar = require('portal.PortalSidebar');
var utils = require('web.utils');
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',
},
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);
/**
* @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);
var $invoiceHtml = this.$el.find('iframe#invoice_html');
var updateIframeSize = this._updateIframeSize.bind(this, $invoiceHtml);
$(window).on('resize', updateIframeSize);
$(window).on('resize', updateIframeSize);
var iframeDoc = $invoiceHtml[0].contentDocument || $invoiceHtml[0].contentWindow.document;
if (iframeDoc.readyState === 'complete') {
updateIframeSize();
} else {
$invoiceHtml.on('load', updateIframeSize);
}
var iframeDoc = $invoiceHtml[0].contentDocument || $invoiceHtml[0].contentWindow.document;
if (iframeDoc.readyState === 'complete') {
updateIframeSize();
} else {
$invoiceHtml.on('load', updateIframeSize);
}
return def;
},
return def;
},
//--------------------------------------------------------------------------
// Handlers
//--------------------------------------------------------------------------
//--------------------------------------------------------------------------
// 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);
/**
* 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);
},
});
// 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";
"use strict";
const { Component } = owl;
const { useState } = owl.hooks;
const AbstractFieldOwl = require('web.AbstractFieldOwl');
const field_registry = require('web.field_registry_owl');
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 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));
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;
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";
"use strict";
var core = require('web.core');
var relational_fields = require('web.relational_fields');
......@@ -23,30 +23,48 @@ odoo.define('account.hierarchy.selection', function (require) {
domain: [],
fields: ['id', 'internal_group', 'display_name'],
},
}).then(function(arg) {
}).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('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('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'])},
{
'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() {
Promise.resolve(prom).then(function () {
self.$el.empty();
self._addHierarchy(self.$el, self.hierarchy_groups, 0);
var value = self.value;
......@@ -56,13 +74,13 @@ odoo.define('account.hierarchy.selection', function (require) {
self.$el.val(JSON.stringify(value));
});
},
_addHierarchy: function(el, group, level) {
_addHierarchy: function (el, group, level) {
var self = this;
_.each(group, function(item) {
_.each(group, function (item) {
var optgroup = $('<optgroup/>').attr(({
'label': $('<div/>').html('&nbsp;'.repeat(6 * level) + item['name']).text(),
}))
_.each(item['ids'], function(id) {
_.each(item['ids'], function (id) {
var value = _.find(self.values, v => v[0] == id)
optgroup.append($('<option/>', {
value: JSON.stringify(value[0]),
......
odoo.define('account.bank_statement', function(require) {
odoo.define('account.bank_statement', function (require) {
"use strict";
var KanbanController = require("web.KanbanController");
......
odoo.define('account.upload.bill.mixin', function (require) {
"use strict";
"use strict";
var core = require('web.core');
var _t = core._t;
......@@ -29,7 +29,7 @@ odoo.define('account.upload.bill.mixin', function (require) {
var self = this;
var attachments = Array.prototype.slice.call(arguments, 1);
// Get id from result
var attachent_ids = attachments.reduce(function(filtered, record) {
var attachent_ids = attachments.reduce(function (filtered, record) {
if (record.id) {
filtered.push(record.id);
}
......@@ -40,7 +40,7 @@ odoo.define('account.upload.bill.mixin', function (require) {
method: 'create_invoice_from_attachment',
args: ["", attachent_ids],
context: this.initialState.context,
}).then(function(result) {
}).then(function (result) {
self.do_action(result);
});
},
......@@ -62,7 +62,7 @@ odoo.define('account.upload.bill.mixin', function (require) {
odoo.define('account.bills.tree', function (require) {
"use strict";
"use strict";
var core = require('web.core');
var ListController = require('web.ListController');
var ListView = require('web.ListView');
......@@ -87,7 +87,7 @@ odoo.define('account.bills.tree', function (require) {
});
odoo.define('account.dashboard.kanban', function (require) {
"use strict";
"use strict";
var core = require('web.core');
var KanbanController = require('web.KanbanController');
var KanbanView = require('web.KanbanView');
......
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: [],
},
};
"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 {
}
async willUpdateProps(nextProps) {
await super.willUpdateProps(nextProps);
Object.assign(this.data, JSON.parse(this.value));
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;
ShowGroupedList.template = 'account.GroupedListTemplate';
ShowGroupedList.components = {ListGroup}
field_registry.add('grouped_view_widget', ShowGroupedList);
return ShowGroupedList;
});
odoo.define('account.activity', function (require) {
"use strict";
"use strict";
var AbstractField = require('web.AbstractField');
var core = require('web.core');
var field_registry = require('web.field_registry');
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 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));
},
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']],
});
},
_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]],
});
}
})
_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);
field_registry.add('kanban_vat_activity', VatActivity);
return 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');
"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 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';
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--;
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');
}
$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);
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);
}
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');
});
}
});
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);
},
});
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);
};
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);
fieldRegistry.add('section_and_note_one2many', SectionAndNoteFieldOne2Many);
fieldRegistry.add('section_and_note_text', SectionAndNoteFieldText);
return SectionAndNoteListRenderer;
return SectionAndNoteListRenderer;
});
......@@ -20,19 +20,19 @@ odoo.define('account.tax_group', function (require) {
//--------------------------------------------------------------------------
/**
* This method is called by "_setTaxGroups". It is
* 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) {
_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){
function applyChange(line_id) {
let debitAmount = 0;
let creditAmount = 0;
let amount_currency = 0;
......@@ -63,14 +63,23 @@ odoo.define('account.tax_group', function (require) {
// 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
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){
if (line_id) {
applyChange(line_id);
} else {
const {limit, id, count} = self.record.data.line_ids;
......@@ -92,7 +101,7 @@ odoo.define('account.tax_group', function (require) {
* 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 () {
......@@ -100,11 +109,11 @@ odoo.define('account.tax_group', function (require) {
},
/**
* This method is part of the widget life cycle and allows you to render
* This method is part of the widget life cycle and allows you to render
* the widget.
*
*
* @private
* @override
* @override
*/
_render: function () {
var self = this;
......@@ -123,11 +132,11 @@ odoo.define('account.tax_group', function (require) {
//--------------------------------------------------------------------------
/**
* This method is called when the user is in edit mode and
* leaves the <input> field. Then, we execute the code that
* 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
*
* @param {event} ev
*/
_onBlur: function (ev) {
ev.preventDefault();
......@@ -147,14 +156,14 @@ odoo.define('account.tax_group', function (require) {
return this._render();
}
var taxGroupId = $input.parents('.oe_tax_group_editable').data('taxGroupId');
this._changeTaxValueByTaxGroup(taxGroupId, oldValue-newValue);
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
*
* @param {event} ev
*/
_onClick: function (ev) {
ev.preventDefault();
......@@ -170,11 +179,11 @@ odoo.define('account.tax_group', function (require) {
},
/**
* 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,
* 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
*
* @param {event} ev
*/
_onKeydown: function (ev) {
switch (ev.which) {
......
odoo.define('account.tour', function(require) {
"use strict";
odoo.define('account.tour', function (require) {
"use strict";
var core = require('web.core');
var tour = require('web_tour.tour');
var core = require('web.core');
var tour = require('web_tour.tour');
var _t = core._t;
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"
}
]);
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;
}
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_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;
}
.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;
}
h4 {
font-size: $font-size-base;
font-weight: 500;
}
.fa-gift {
color: #eeeeee;
&:hover {
color: #555555;
}
}
.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');
}
.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');
}
.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 {
.o_kanban_record {
@include media-breakpoint-up(sm) {
.oe_kanban_action_button {
display: block;
margin-bottom: 5px;
}
}
@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;
.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;
border-top: 1px solid;
border-color: $o-brand-lightsecondary;
}
&.fa-star-o {
color: $o-main-color-muted;
&:hover {
color: gold;
}
}
&.fa-star {
color: gold;
}
}
.o_dashboard_star {
font-size: 12px;
&.fa-star-o {
color: $o-main-color-muted;
.o_dashboard_graph {
margin-bottom: -$o-horizontal-padding/2;
&:hover {
color: gold;
}
}
&.fa-star {
color: gold;
}
}
&.o_kanban_ungrouped {
.o_kanban_record {
width: 450px;
}
.o_dashboard_graph {
margin-bottom: -$o-horizontal-padding/2;
}
}
.o_kanban_group {
&:not(.o_column_folded) {
width: 450px + 2*$o-kanban-group-padding;
&.o_kanban_ungrouped {
.o_kanban_record {
width: 450px;
}
}
@include media-breakpoint-down(sm) {
width: 100%;
}
}
.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;
position: relative;
margin: 16px -16px;
canvas {
height: 75px;
}
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;
fill: gray !important;
opacity: 0.1;
}
.o_search_panel.account_root {
flex: 0 0 50px;
padding: 6px;
scrollbar-width: thin;
.o_search_panel_section_header {
display: none;
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;
}
.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;
.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;
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;
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;
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_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;
}
}
}
......@@ -6,14 +6,14 @@ $o-account-info-color: #44c;
@keyframes animate-red {
0% {
color: red;
}
100% {
color: inherit;
}
0% {
color: red;
}
100% {
color: inherit;
}
}
.animate {
animation: animate-red 1s ease;
animation: animate-red 1s ease;
}
......@@ -2,16 +2,21 @@
<templates>
<t t-name="accountJournalDashboardActivity">
<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">
<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>
<span>
<t t-esc="activity.date"/>
</span>
</div>
</div>
</t>
......
......@@ -14,22 +14,29 @@
<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>
<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>
<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">
<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>
<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>
<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;">
<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>
......@@ -60,7 +67,7 @@
</t>
</td>
</tr>
<tr>
<tr>
<td><strong>Memo: </strong></td>
<td>
<div style="width: 200px; word-wrap: break-word">
......@@ -74,12 +81,16 @@
</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>
<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>
<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>
......@@ -3,11 +3,13 @@
<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>
<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>
......@@ -18,8 +20,10 @@
<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' : ''}}"/>
<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>
<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>
<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>
<span>
<t t-esc="data.options.discarded_number"/>
are not shown in the preview
</span>
</t>
</div>
......
......@@ -18,7 +18,8 @@
</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]"/>
<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">
......
odoo.define('account.reconciliation_field_tests', function (require) {
"use strict";
"use strict";
var FormView = require('web.FormView');
var testUtils = require('web.test_utils');
var FormView = require('web.FormView');
var testUtils = require('web.test_utils');
var createView = testUtils.createView;
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"},
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"}',
}]
},
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');
};
}
}, function () {
QUnit.module('Reconciliation');
QUnit.test('Reconciliation form field', async function (assert) {
assert.expect(5);
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");
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");
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');
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");
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_open_payment').trigger('click');
form.$('.o_field_widget[name="payments_widget"] .js_payment_info').trigger('focus');
form.$('.popover .js_unreconcile_payment').trigger('click');
form.$('.o_field_widget[name="payments_widget"] .js_payment_info').trigger('focus');
form.$('.popover .js_unreconcile_payment').trigger('click');
form.destroy();
form.destroy();
});
});
});
});
odoo.define('account.section_and_note_tests', function (require) {
"use strict";
"use strict";
var FormView = require('web.FormView');
var testUtils = require('web.test_utils');
var createView = testUtils.createView;
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'
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]},
],
},
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'
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'},
]
},
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>' +
};
},
}, 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,
});
'</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');
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)');
// 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");
assert.doesNotHaveClass($tr0, 'o_is_line_section',
"should not have a section class");
var $tr1 = form.$('tr.o_data_row:eq(1)');
var $tr1 = form.$('tr.o_data_row:eq(1)');
assert.hasClass($tr1, 'o_is_line_section',
"should have a section class");
assert.hasClass($tr1, 'o_is_line_section',
"should have a section class");
// enter edit mode
await testUtils.form.clickEdit(form);
// 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 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");
// 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();
form.destroy();
});
});
});
});
......@@ -10,33 +10,33 @@ odoo.define('account.dashboard.setup.tour', function (require) {
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.');
}
},
}
]);
{
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.');
}
},
}
]);
});
......@@ -17,7 +17,9 @@
<field name="model">res.district</field>
<field name="arch" type="xml">
<tree string="Kabupaten/Kota" sample="1">
<field name="display_code" string="Kode"/>
<field name="display_code" string="Prov"/>
<field name="typ" string="Jenis"/>
<field name="code" string="Kode"/>
<field name="name" string="Nama"/>
</tree>
</field>
......@@ -43,6 +45,7 @@
<form>
<group>
<field name="state_id" string="Provinsi"/>
<field name="typ" string="Jenis"/>
<field name="code" string="Kabupaten/Kota"/>
<field name="display_code" string="Full Kode"/>
<field name="name" string="Nama"/>
......
......@@ -47,19 +47,19 @@
<field name="inherit_id" ref="account.product_template_form_view"/>
<field name="arch" type="xml">
<!-- <xpath expr="//page[@name='general_information']" position="replace"/>-->
<!-- <xpath expr="//page[@name='general_information']" position="replace"/>-->
<xpath expr="//page[@name='inventory']" position="replace"/>
<xpath expr="//page[@name='sales']" position="replace"/>
<xpath expr="//page[@name='purchase']" position="replace"/>
<!-- <xpath expr="//div[@name='options']" position="after">-->
<!-- Menambah field setelah pricing -->
<!-- <field name="active" invisible=""/>-->
<!-- <field name="categ_id" invisible="0"/>-->
<!-- </xpath>-->
<!-- <xpath expr="//div[@name='default_code']" position="attribute">-->
<!-- <field name="string" string="NOPD"/>-->
<!-- </xpath>-->
<!-- <xpath expr="//div[@name='options']" position="after">-->
<!-- Menambah field setelah pricing -->
<!-- <field name="active" invisible=""/>-->
<!-- <field name="categ_id" invisible="0"/>-->
<!-- </xpath>-->
<!-- <xpath expr="//div[@name='default_code']" position="attribute">-->
<!-- <field name="string" string="NOPD"/>-->
<!-- </xpath>-->
</field>
</record>
......
......@@ -60,16 +60,16 @@
parent="config_pdl_kab_menu"
action="action_district_config_pdl_kab"
sequence="2"/>
<!-- <menuitem id="sub_district_config_pdl_kab_menu"-->
<!-- name="Kecamatan"-->
<!-- parent="config_pdl_kab_menu"-->
<!-- action="action_sub_district_config_pdl_kab"-->
<!-- sequence="2"/>-->
<!-- <menuitem id="village_config_pdl_kab_menu"-->
<!-- name="Desa/Kelurahan"-->
<!-- parent="config_pdl_kab_menu"-->
<!-- action="action_village_config_pdl_kab"-->
<!-- sequence="2"/>-->
<menuitem id="sub_district_config_pdl_kab_menu"
name="Kecamatan"
parent="config_pdl_kab_menu"
action="action_sub_district_config_pdl_kab"
sequence="2"/>
<menuitem id="village_config_pdl_kab_menu"
name="Desa/Kelurahan"
parent="config_pdl_kab_menu"
action="action_village_config_pdl_kab"
sequence="2"/>
<menuitem id="sudut_pandang_config_pdl_kab_menu"
name="Sudut Pandang"
parent="config_pdl_kab_menu"
......
......@@ -7,6 +7,7 @@
<field name="arch" type="xml">
<tree string="Kecamatan" sample="1">
<field name="display_code" string="Kode"/>
<field name="code" string="Kode"/>
<field name="name" string="Nama"/>
</tree>
</field>
......@@ -25,8 +26,8 @@
</record>
<record id="sub_district_template_form" model="ir.ui.view">
<field name="name">sub_district.template.form</field>
<field name="model">res.sub_district</field>
<field name="name">sub.district.template.form</field>
<field name="model">res.district.sub</field>
<field name="priority">4</field>
<field name="arch" type="xml">
<form>
......
......@@ -3,37 +3,39 @@
<data>
<record id="village_template_tree" model="ir.ui.view">
<field name="name">sub.district.template.tree</field>
<field name="model">res.district.sub</field>
<field name="model">res.district.village</field>
<field name="arch" type="xml">
<tree string="Kecamatan" sample="1">
<tree string="Desa/Kelurahan" sample="1">
<field name="display_code" string="Kode"/>
<field name="code" string="Kode"/>
<field name="name" string="Nama"/>
</tree>
</field>
</record>
<record id="action_village_config_pdl_kab" model="ir.actions.act_window">
<field name="name">Kecamatan</field>
<field name="res_model">res.district.sub</field>
<field name="name">Desa/Kelurahan</field>
<field name="res_model">res.district.village</field>
<field name="view_mode">kanban,tree,form</field>
<field name="view_id" ref="village_template_tree"/>
<field name="help" type="html">
<p class="o_view_nocontent_smiling_face">
Kecamatan
Desa/Kelurahan
</p>
</field>
</record>
<record id="village_template_form" model="ir.ui.view">
<field name="name">village.template.form</field>
<field name="model">res.village</field>
<field name="model">res.district.village</field>
<field name="priority">4</field>
<field name="arch" type="xml">
<form>
<group>
<field name="display_code" string="Full Kode"/>
<field name="sub_district_id" string="Kecamatan"/>
<field name="typ" string="Jenis"/>
<field name="code" string="Desa/Kelurahan"/>
<field name="display_code" string="Full Kode"/>
<field name="name" string="Nama"/>
</group>
</form>
......
Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!