Merge lp:~akretion-team/account-closing/70-cutoff-modules into lp:~account-core-editors/account-closing/7.0

Proposed by Alexis de Lattre
Status: Merged
Approved by: Yannick Vaucher @ Camptocamp
Approved revision: 9
Merged at revision: 36
Proposed branch: lp:~akretion-team/account-closing/70-cutoff-modules
Merge into: lp:~account-core-editors/account-closing/7.0
Diff against target: 3431 lines (+3223/-0)
35 files modified
account_cutoff_accrual_base/__init__.py (+25/-0)
account_cutoff_accrual_base/__openerp__.py (+46/-0)
account_cutoff_accrual_base/account.py (+36/-0)
account_cutoff_accrual_base/account_cutoff.py (+57/-0)
account_cutoff_accrual_base/account_cutoff_view.xml (+86/-0)
account_cutoff_accrual_base/account_view.xml (+28/-0)
account_cutoff_accrual_base/company.py (+37/-0)
account_cutoff_accrual_base/company_view.xml (+26/-0)
account_cutoff_accrual_base/i18n/account_cutoff_accrual_base.pot (+114/-0)
account_cutoff_accrual_picking/__init__.py (+23/-0)
account_cutoff_accrual_picking/__openerp__.py (+61/-0)
account_cutoff_accrual_picking/account_cutoff.py (+220/-0)
account_cutoff_accrual_picking/account_cutoff_view.xml (+54/-0)
account_cutoff_accrual_picking/i18n/account_cutoff_accrual_picking.pot (+78/-0)
account_cutoff_base/__init__.py (+24/-0)
account_cutoff_base/__openerp__.py (+47/-0)
account_cutoff_base/account_cutoff.py (+445/-0)
account_cutoff_base/account_cutoff_view.xml (+240/-0)
account_cutoff_base/company.py (+35/-0)
account_cutoff_base/company_view.xml (+27/-0)
account_cutoff_base/i18n/account_cutoff_base.pot (+444/-0)
account_cutoff_base/security/ir.model.access.csv (+9/-0)
account_cutoff_prepaid/__init__.py (+26/-0)
account_cutoff_prepaid/__openerp__.py (+57/-0)
account_cutoff_prepaid/account.py (+150/-0)
account_cutoff_prepaid/account_cutoff.py (+193/-0)
account_cutoff_prepaid/account_cutoff_view.xml (+115/-0)
account_cutoff_prepaid/account_invoice_view.xml (+60/-0)
account_cutoff_prepaid/account_view.xml (+53/-0)
account_cutoff_prepaid/company.py (+37/-0)
account_cutoff_prepaid/company_view.xml (+27/-0)
account_cutoff_prepaid/i18n/account_cutoff_prepaid.pot (+242/-0)
account_cutoff_prepaid/product.py (+36/-0)
account_cutoff_prepaid/product_demo.xml (+25/-0)
account_cutoff_prepaid/product_view.xml (+40/-0)
To merge this branch: bzr merge lp:~akretion-team/account-closing/70-cutoff-modules
Reviewer Review Type Date Requested Status
Yannick Vaucher @ Camptocamp code review, no tests Approve
Maxime Chambreuil (http://www.savoirfairelinux.com) code review Approve
Raphaël Valyi - http://www.akretion.com Approve
Guewen Baconnier @ Camptocamp code review Approve
Review via email: mp+185992@code.launchpad.net

Description of the change

My development on cut-offs for OpenERP 7.0 is ready for merging !

I already made a functionnal review with Frédéric Clementi (C2C).

To post a comment you must log in.
2. By Alexis de Lattre

Coding style enhancements (osv.Model -> orm.Model, from . import xxx)

Revision history for this message
Guewen Baconnier @ Camptocamp (gbaconnier-c2c) wrote :

Hi,

Why do you wrote this condition like that:

    'accrued' not in context.get('type', '-') and True or False

Can't you write?

    'accrued' not in context.get('type')

l.510 and some other places:

  if len(ids) != 1: raise

You can't do that, 'raise' without exception is solely used to reraise the *current* exception in an exception handler. Here, it will fail with a TypeError. Prefer:

  assert len(ids) == 1

l.524-525,1814 you don't need to check if to_delete_line_ids is empty because unlink will return early if it was.

l.530: remove .keys(): if cur_cutoff['type'] not in pick_type_map:
l.531 raise # this should never happen => as before, raise alone can be used here, in fact you want to do:

    assert cur_cutoff['type'] in pick_type_map

l.509 get_lines_from_picking()
l.989 create_move()
l.1802 get_prepaid_lines()
Aren't these methods good candidates for '_prepare' methods?

l.1043 context['account_period_prefer_normal'] = True
The context can be None; it must be copied before you alter it to avoid propagation upstream, so you may want to add:
    if context is None:
        context = {}
    else:
        context = context.copy()

l.1656-1668, 1688-1702: I don't think that's allowed and valid to raise errors inside a _constraints, but I may be wrong. In any case, in orm.py there is no error handling around the _constraints functions so the exception will be caught by the general exception handler and we'll loose the handling of the _constraint ('Error occured while validating the fields...').

Overall:
 - some lines too long
 - no space before colon (e.g. 'Error:', not 'Error :')
 - you don't need to use .keys() on the dictionaries when you work with the keys
 - On the indentation (pep8):

    to_delete_line_ids = line_obj.search(cr, uid, [
        ('parent_id', '=', cur_cutoff['id']),
        ('stock_move_id', '!=', False)
        ], context=context) or
    'account_id': fields.many2one('account.account', 'Regular Account',
        domain=[('type','<>','view')], required=True),

   are wrong ("Arguments on first line forbidden when not using vertical alignment"). Please refer to http://www.python.org/dev/peps/pep-0008/#indentation
 - on the blank lines (pep8): "Separate top-level function and class definitions with two blank lines.", "Method definitions inside a class are separated by a single blank line.", more at: http://www.python.org/dev/peps/pep-0008/#blank-lines

(I put the last 2 points to pep8 for the reference so you know, I won't refuse the merge because you have an extra blank line)

Thanks for your work!

review: Needs Fixing
Revision history for this message
Ronald Portier (Therp) (rportier1962) wrote :

One remark on the preview done by Guewen:

It IS valid to raise an error inside a constraint checking function. Actually it is the ONLY way to give a precise error message, when more then one error can be detected.

3. By Alexis de Lattre

Add _prepare functions to allow to inherit before create
Use assert
Remove .keys()
No space before colon
PEP8/Flake8 : getting closer to compliancy

4. By Alexis de Lattre

Forgot to move some code to the new _prepare function.

Revision history for this message
Alexis de Lattre (alexis-via) wrote :

@guewen
I took into account almost all your remarks :
- I add the _prepare functions (it was in my roadmap to develop them :)
- I now use assert instead of a dirty raise
- I don't use .keys() anymore
- No space before colon in English :)
- better handling of context in context['account_period_prefer_normal']
- PEP8 stuff

About my dirty lines :

    'accrued' not in context.get('type', '-') and True or False

I would prefer to use the line you suggest :

    'accrued' not in context.get('type')

but, with the above line, if there is no 'type' key in context, then it crashes (I must have a string after the 'in')

About your remark "you don't need to check if to_delete_line_ids is empty because unlink will return early if it was". You are certainly right, but I still prefer to use my "if to_delete_line_ids" because I find it more logic for the reader.

As Ronald said, using raise inside constraint checking functions is the only way to have an error message that contain relevant information inside the message. It is a technique I use very often in my code. I didn't invent it myself, I learnt it in this blog post by Albert from Nan-tic http://www.nan-tic.com/en/2010/programming-tips-constraints-and-exceptions/

Revision history for this message
Guewen Baconnier @ Camptocamp (gbaconnier-c2c) wrote :

Hi,

Thanks for your changes Alexis.

For the: "'accrued' not in context.get('type', '-') and True or False", you are right for the first part, still I find weird the "and True or False", is it a requisite for the XML view?

I'm on the departure for 10 days without internet connection and would have the time now to continue the review. I'm changing my review to 'Abstain' to avoid to penalize your MP with a 'Needs fixing' status.

review: Abstain
Revision history for this message
Guewen Baconnier @ Camptocamp (gbaconnier-c2c) wrote :

> I'm on the departure for 10 days without internet connection and would have
> the time now to continue the review. I'm changing my review to 'Abstain' to
> avoid to penalize your MP with a 'Needs fixing' status.

s/would have the time now to continue the review./won't have the time now to continue the review./

5. By Alexis de Lattre

Remove the unnecessary "and True or False" after 'xxx' not in context.get('type', '-')

Revision history for this message
Alexis de Lattre (alexis-via) wrote :

I removed the "and True or False" after 'xxx' not in context.get('type', '-') ; I tested the views and everything is OK.

6. By Alexis de Lattre

prepaid cutoffs : don't take into account the move lines dated after cut-off date.

Revision history for this message
Lorenzo Battistini (elbati) wrote :

We tested 'account_cutoff_prepaid' and 'account_cutoff_base' and they work well.
Thanks Alexis!

Revision history for this message
Guewen Baconnier @ Camptocamp (gbaconnier-c2c) wrote :

Hi Alexis,

Thanks for your changes!

I'm back from vacation since weeks now, so it's time to come back to this proposal!

There is still a 'raise' alone at line 557.
Otherwise, nothing struck me.

7. By Alexis de Lattre

Replace a lonely raise by an assert

Revision history for this message
Alexis de Lattre (alexis-via) wrote :

@Lorenzo
You're welcome ! I am happy that you like my modules.

@Guewen
I replaced the raise by an assert

Revision history for this message
Guewen Baconnier @ Camptocamp (gbaconnier-c2c) wrote :

Thanks Alexis for taking up the changes!

Finally: LGTM :-)

Lorenzo, does your comment count as an 'Approved'?

review: Approve (code review)
Revision history for this message
Raphaël Valyi - http://www.akretion.com (rvalyi) wrote :

LGTM, no tests

review: Approve
Revision history for this message
Yannick Vaucher @ Camptocamp (yvaucher-c2c) wrote :

Hello Alexis,

Can you add translation pot files?

l.1745 can you split your tiny comment ?
With it I can't have twice your code aside on a single screen (not a so tiny one) in my vim =)

And other lines that are a bit too long
account_cutoff_prepaid/account.py|53 col 80| E501 line too long (252 > 79 characters)

account_cutoff_prepaid/product.py|33 col 80| E501 line too long (148 > 79 characters)
account_cutoff_prepaid/account.py|51 col 80| E501 line too long (119 > 79 characters)
account_cutoff_prepaid/account.py|89 col 80| E501 line too long (101 > 79 characters)
account_cutoff_prepaid/account.py|131 col 80| E501 line too long (155 > 79 characters)
account_cutoff_base/account_cutoff.py|307 col 80| E501 line too long (172 > 79 characters)
account_cutoff_base/account_cutoff.py|230 col 80| E501 line too long (144 > 79 characters)
account_cutoff_base/account_cutoff.py|232 col 80| E501 line too long (123 > 79 characters)
account_cutoff_base/account_cutoff.py|239 col 80| E501 line too long (117 > 79 characters)
account_cutoff_base/account_cutoff.py|242 col 80| E501 line too long (116 > 79 characters)
account_cutoff_base/account_cutoff.py|245 col 80| E501 line too long (109 > 79 characters)
account_cutoff_base/account_cutoff.py|246 col 80| E501 line too long (133 > 79 characters)
account_cutoff_base/account_cutoff.py|248 col 80| E501 line too long (132 > 79 characters)
account_cutoff_base/account_cutoff.py|80 col 80| E501 line too long (159 > 79 characters)
account_cutoff_base/account_cutoff.py|105 col 80| E501 line too long (136 > 79 characters)

And space after coma is required in PEP8 can you add it in your domains

review: Needs Fixing (code review, no tests)
8. By Alexis de Lattre

Reduce flake8 warnings (cut lines and comments, space after coma inside domains)
On account.account, type must be <> 'view' and <> 'closed'

9. By Alexis de Lattre

My christmas present to the PEP8 fundamentalists : there is not even a single warning left !
Add translation template files.

Revision history for this message
Alexis de Lattre (alexis-via) wrote :

@Yannick

All your remarks are now integrated.

Revision history for this message
Maxime Chambreuil (http://www.savoirfairelinux.com) (max3903) :
review: Approve (code review)
Revision history for this message
Yannick Vaucher @ Camptocamp (yvaucher-c2c) wrote :

Thanks for the Christmas present :)

review: Approve (code review, no tests)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== added directory 'account_cutoff_accrual_base'
2=== added file 'account_cutoff_accrual_base/__init__.py'
3--- account_cutoff_accrual_base/__init__.py 1970-01-01 00:00:00 +0000
4+++ account_cutoff_accrual_base/__init__.py 2013-12-24 15:32:24 +0000
5@@ -0,0 +1,25 @@
6+# -*- encoding: utf-8 -*-
7+##############################################################################
8+#
9+# Account Cut-off Accrual Base module for OpenERP
10+# Copyright (C) 2013 Akretion (http://www.akretion.com)
11+# @author Alexis de Lattre <alexis.delattre@akretion.com>
12+#
13+# This program is free software: you can redistribute it and/or modify
14+# it under the terms of the GNU Affero General Public License as
15+# published by the Free Software Foundation, either version 3 of the
16+# License, or (at your option) any later version.
17+#
18+# This program is distributed in the hope that it will be useful,
19+# but WITHOUT ANY WARRANTY; without even the implied warranty of
20+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21+# GNU Affero General Public License for more details.
22+#
23+# You should have received a copy of the GNU Affero General Public License
24+# along with this program. If not, see <http://www.gnu.org/licenses/>.
25+#
26+##############################################################################
27+
28+from . import company
29+from . import account
30+from . import account_cutoff
31
32=== added file 'account_cutoff_accrual_base/__openerp__.py'
33--- account_cutoff_accrual_base/__openerp__.py 1970-01-01 00:00:00 +0000
34+++ account_cutoff_accrual_base/__openerp__.py 2013-12-24 15:32:24 +0000
35@@ -0,0 +1,46 @@
36+# -*- encoding: utf-8 -*-
37+##############################################################################
38+#
39+# Account Cutoff Accrual Base module for OpenERP
40+# Copyright (C) 2013 Akretion (http://www.akretion.com)
41+# @author Alexis de Lattre <alexis.delattre@akretion.com>
42+#
43+# This program is free software: you can redistribute it and/or modify
44+# it under the terms of the GNU Affero General Public License as
45+# published by the Free Software Foundation, either version 3 of the
46+# License, or (at your option) any later version.
47+#
48+# This program is distributed in the hope that it will be useful,
49+# but WITHOUT ANY WARRANTY; without even the implied warranty of
50+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
51+# GNU Affero General Public License for more details.
52+#
53+# You should have received a copy of the GNU Affero General Public License
54+# along with this program. If not, see <http://www.gnu.org/licenses/>.
55+#
56+##############################################################################
57+
58+
59+{
60+ 'name': 'Account Accrual Base',
61+ 'version': '0.1',
62+ 'category': 'Accounting & Finance',
63+ 'license': 'AGPL-3',
64+ 'summary': 'Base module for accrued expenses and revenues',
65+ 'description': """This module contains objets, fields and menu entries that are used by other accrual modules. So you need to install other accrual modules to get the additionnal functionalities :
66+- the module 'account_cutoff_accrual_picking' will manage accrued expenses and revenues based on pickings.
67+- a not-developped-yet module will manage accrued expenses and revenues based on timesheets.
68+
69+Please contact Alexis de Lattre from Akretion <alexis.delattre@akretion.com> for any help or question about this module.
70+ """,
71+ 'author': 'Akretion',
72+ 'website': 'http://www.akretion.com',
73+ 'depends': ['account_cutoff_base'],
74+ 'data': [
75+ 'company_view.xml',
76+ 'account_view.xml',
77+ 'account_cutoff_view.xml',
78+ ],
79+ 'installable': True,
80+ 'active': False,
81+}
82
83=== added file 'account_cutoff_accrual_base/account.py'
84--- account_cutoff_accrual_base/account.py 1970-01-01 00:00:00 +0000
85+++ account_cutoff_accrual_base/account.py 2013-12-24 15:32:24 +0000
86@@ -0,0 +1,36 @@
87+# -*- encoding: utf-8 -*-
88+##############################################################################
89+#
90+# Account Cut-off Accrual Base module for OpenERP
91+# Copyright (C) 2013 Akretion (http://www.akretion.com)
92+# @author Alexis de Lattre <alexis.delattre@akretion.com>
93+#
94+# This program is free software: you can redistribute it and/or modify
95+# it under the terms of the GNU Affero General Public License as
96+# published by the Free Software Foundation, either version 3 of the
97+# License, or (at your option) any later version.
98+#
99+# This program is distributed in the hope that it will be useful,
100+# but WITHOUT ANY WARRANTY; without even the implied warranty of
101+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
102+# GNU Affero General Public License for more details.
103+#
104+# You should have received a copy of the GNU Affero General Public License
105+# along with this program. If not, see <http://www.gnu.org/licenses/>.
106+#
107+##############################################################################
108+
109+from openerp.osv import orm, fields
110+
111+
112+class account_tax(orm.Model):
113+ _inherit = 'account.tax'
114+
115+ _columns = {
116+ 'account_accrued_revenue_id': fields.many2one(
117+ 'account.account', 'Accrued Revenue Tax Account',
118+ domain=[('type', '<>', 'view'), ('type', '<>', 'closed')]),
119+ 'account_accrued_expense_id': fields.many2one(
120+ 'account.account', 'Accrued Expense Tax Account',
121+ domain=[('type', '<>', 'view'), ('type', '<>', 'closed')]),
122+ }
123
124=== added file 'account_cutoff_accrual_base/account_cutoff.py'
125--- account_cutoff_accrual_base/account_cutoff.py 1970-01-01 00:00:00 +0000
126+++ account_cutoff_accrual_base/account_cutoff.py 2013-12-24 15:32:24 +0000
127@@ -0,0 +1,57 @@
128+# -*- encoding: utf-8 -*-
129+##############################################################################
130+#
131+# Account Cut-off Accrual Base module for OpenERP
132+# Copyright (C) 2013 Akretion (http://www.akretion.com)
133+# @author Alexis de Lattre <alexis.delattre@akretion.com>
134+#
135+# This program is free software: you can redistribute it and/or modify
136+# it under the terms of the GNU Affero General Public License as
137+# published by the Free Software Foundation, either version 3 of the
138+# License, or (at your option) any later version.
139+#
140+# This program is distributed in the hope that it will be useful,
141+# but WITHOUT ANY WARRANTY; without even the implied warranty of
142+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
143+# GNU Affero General Public License for more details.
144+#
145+# You should have received a copy of the GNU Affero General Public License
146+# along with this program. If not, see <http://www.gnu.org/licenses/>.
147+#
148+##############################################################################
149+
150+
151+from openerp.osv import orm, fields
152+import openerp.addons.decimal_precision as dp
153+
154+
155+class account_cutoff(orm.Model):
156+ _inherit = 'account.cutoff'
157+
158+ def _inherit_default_cutoff_account_id(self, cr, uid, context=None):
159+ if context is None:
160+ context = {}
161+ account_id = super(account_cutoff, self).\
162+ _inherit_default_cutoff_account_id(
163+ cr, uid, context=context)
164+ type = context.get('type')
165+ company = self.pool['res.users'].browse(
166+ cr, uid, uid, context=context).company_id
167+ if type == 'accrued_expense':
168+ account_id = company.default_accrued_expense_account_id.id or False
169+ elif type == 'accrued_revenue':
170+ account_id = company.default_accrued_revenue_account_id.id or False
171+ return account_id
172+
173+
174+class account_cutoff_line(orm.Model):
175+ _inherit = 'account.cutoff.line'
176+
177+ _columns = {
178+ 'quantity': fields.float(
179+ 'Quantity', digits_compute=dp.get_precision('Product UoS'),
180+ readonly=True),
181+ 'price_unit': fields.float(
182+ 'Unit Price', digits_compute=dp.get_precision('Product Price'),
183+ readonly=True, help="Price per unit (discount included)"),
184+ }
185
186=== added file 'account_cutoff_accrual_base/account_cutoff_view.xml'
187--- account_cutoff_accrual_base/account_cutoff_view.xml 1970-01-01 00:00:00 +0000
188+++ account_cutoff_accrual_base/account_cutoff_view.xml 2013-12-24 15:32:24 +0000
189@@ -0,0 +1,86 @@
190+<?xml version="1.0" encoding="utf-8"?>
191+
192+<!--
193+ Copyright (C) 2013 Akretion (http://www.akretion.com/)
194+ @author Alexis de Lattre <alexis.delattre@akretion.com>
195+ The licence is in the file __openerp__.py
196+-->
197+
198+<openerp>
199+<data>
200+
201+<!-- Form view for lines -->
202+<record id="account_cutoff_line_form" model="ir.ui.view">
203+ <field name="name">accrual.account_cutoff_line</field>
204+ <field name="model">account.cutoff.line</field>
205+ <field name="inherit_id" ref="account_cutoff_base.account_cutoff_line_form"/>
206+ <field name="arch" type="xml">
207+ <field name="amount" position="before">
208+ <field name="quantity" invisible="'accrued' not in context.get('type', '-')"/>
209+ <field name="price_unit" widget="monetary" options="{'currency_field': 'currency_id'}" invisible="'accrued' not in context.get('type', '-')"/>
210+ </field>
211+ </field>
212+</record>
213+
214+<!-- Tree view for lines -->
215+<record id="account_cutoff_line_tree" model="ir.ui.view">
216+ <field name="name">accrual.account_cutoff_line_tree</field>
217+ <field name="model">account.cutoff.line</field>
218+ <field name="inherit_id" ref="account_cutoff_base.account_cutoff_line_tree"/>
219+ <field name="arch" type="xml">
220+ <field name="analytic_account_code" position="after">
221+ <field name="quantity" invisible="'accrued' not in context.get('type', '-')"/>
222+ <field name="price_unit" invisible="'accrued' not in context.get('type', '-')"/>
223+ </field>
224+ </field>
225+</record>
226+
227+
228+<record id="account_expense_accrual_action" model="ir.actions.act_window">
229+ <field name="name">Accrued Expense</field>
230+ <field name="res_model">account.cutoff</field>
231+ <field name="view_type">form</field>
232+ <field name="view_mode">tree,form</field>
233+ <field name="domain">[('type', '=', 'accrued_expense')]</field>
234+ <field name="context">{'type': 'accrued_expense'}</field>
235+ <field name="help" type="html">
236+ <p class="oe_view_nocontent_create">
237+ Click to start preparing a new expense accrual.
238+ </p><p>
239+ This view can be used by accountants in order to collect information about accrued expenses. It then allows to generate the corresponding cut-off journal entry in one click.
240+ </p>
241+ </field>
242+</record>
243+
244+
245+<menuitem id="account_expense_accrual_menu"
246+ parent="account_cutoff_base.cutoff_menu"
247+ action="account_expense_accrual_action"
248+ sequence="35"/>
249+
250+
251+<record id="account_revenue_accrual_action" model="ir.actions.act_window">
252+ <field name="name">Accrued Revenue</field>
253+ <field name="res_model">account.cutoff</field>
254+ <field name="view_type">form</field>
255+ <field name="view_mode">tree,form</field>
256+ <field name="domain">[('type', '=', 'accrued_revenue')]</field>
257+ <field name="context">{'type': 'accrued_revenue'}</field>
258+ <field name="help" type="html">
259+ <p class="oe_view_nocontent_create">
260+ Click to start preparing a new revenue accrual.
261+ </p><p>
262+ This view can be used by accountants in order to collect information about accrued revenue. It then allows to generate the corresponding cut-off journal entry in one click.
263+ </p>
264+ </field>
265+</record>
266+
267+
268+<menuitem id="account_revenue_accrual_menu"
269+ parent="account_cutoff_base.cutoff_menu"
270+ action="account_revenue_accrual_action"
271+ sequence="30"/>
272+
273+
274+</data>
275+</openerp>
276
277=== added file 'account_cutoff_accrual_base/account_view.xml'
278--- account_cutoff_accrual_base/account_view.xml 1970-01-01 00:00:00 +0000
279+++ account_cutoff_accrual_base/account_view.xml 2013-12-24 15:32:24 +0000
280@@ -0,0 +1,28 @@
281+<?xml version="1.0" encoding="utf-8"?>
282+
283+<!--
284+ Copyright (C) 2013 Akretion (http://www.akretion.com/)
285+ @author Alexis de Lattre <alexis.delattre@akretion.com>
286+ The licence is in the file __openerp__.py
287+-->
288+
289+<openerp>
290+<data>
291+
292+<record id="view_tax_form" model="ir.ui.view">
293+ <field name="name">account.cutoff.accrual.view_tax_form</field>
294+ <field name="model">account.tax</field>
295+ <field name="inherit_id" ref="account.view_tax_form" />
296+ <field name="arch" type="xml">
297+ <group string="Refunds" position="after">
298+ <group string="Accruals" name="accrual">
299+ <field name="account_accrued_revenue_id" attrs="{'invisible': [('type_tax_use', '=', 'purchase')]}"/>
300+ <field name="account_accrued_expense_id" attrs="{'invisible': [('type_tax_use', '=', 'sale')]}"/>
301+ </group>
302+ </group>
303+ </field>
304+</record>
305+
306+
307+</data>
308+</openerp>
309
310=== added file 'account_cutoff_accrual_base/company.py'
311--- account_cutoff_accrual_base/company.py 1970-01-01 00:00:00 +0000
312+++ account_cutoff_accrual_base/company.py 2013-12-24 15:32:24 +0000
313@@ -0,0 +1,37 @@
314+# -*- encoding: utf-8 -*-
315+##############################################################################
316+#
317+# Account Cut-off Accrual Base module for OpenERP
318+# Copyright (C) 2013 Akretion (http://www.akretion.com)
319+# @author Alexis de Lattre <alexis.delattre@akretion.com>
320+#
321+# This program is free software: you can redistribute it and/or modify
322+# it under the terms of the GNU Affero General Public License as
323+# published by the Free Software Foundation, either version 3 of the
324+# License, or (at your option) any later version.
325+#
326+# This program is distributed in the hope that it will be useful,
327+# but WITHOUT ANY WARRANTY; without even the implied warranty of
328+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
329+# GNU Affero General Public License for more details.
330+#
331+# You should have received a copy of the GNU Affero General Public License
332+# along with this program. If not, see <http://www.gnu.org/licenses/>.
333+#
334+##############################################################################
335+
336+
337+from openerp.osv import orm, fields
338+
339+
340+class res_company(orm.Model):
341+ _inherit = 'res.company'
342+
343+ _columns = {
344+ 'default_accrued_revenue_account_id': fields.many2one(
345+ 'account.account', 'Default Account for Accrued Revenues',
346+ domain=[('type', '<>', 'view'), ('type', '<>', 'closed')]),
347+ 'default_accrued_expense_account_id': fields.many2one(
348+ 'account.account', 'Default Account for Accrued Expenses',
349+ domain=[('type', '<>', 'view'), ('type', '<>', 'closed')]),
350+ }
351
352=== added file 'account_cutoff_accrual_base/company_view.xml'
353--- account_cutoff_accrual_base/company_view.xml 1970-01-01 00:00:00 +0000
354+++ account_cutoff_accrual_base/company_view.xml 2013-12-24 15:32:24 +0000
355@@ -0,0 +1,26 @@
356+<?xml version="1.0" encoding="utf-8"?>
357+
358+<!--
359+ Copyright (C) 2013 Akretion (http://www.akretion.com/)
360+ @author Alexis de Lattre <alexis.delattre@akretion.com>
361+ The licence is in the file __openerp__.py
362+-->
363+
364+<openerp>
365+<data>
366+
367+<record id="view_company_form" model="ir.ui.view">
368+ <field name="name">accrual.base.company.form</field>
369+ <field name="model">res.company</field>
370+ <field name="inherit_id" ref="account_cutoff_base.view_company_form" />
371+ <field name="arch" type="xml">
372+ <field name="default_cutoff_journal_id" position="after">
373+ <field name="default_accrued_revenue_account_id" />
374+ <field name="default_accrued_expense_account_id" />
375+ </field>
376+ </field>
377+</record>
378+
379+
380+</data>
381+</openerp>
382
383=== added directory 'account_cutoff_accrual_base/i18n'
384=== added file 'account_cutoff_accrual_base/i18n/account_cutoff_accrual_base.pot'
385--- account_cutoff_accrual_base/i18n/account_cutoff_accrual_base.pot 1970-01-01 00:00:00 +0000
386+++ account_cutoff_accrual_base/i18n/account_cutoff_accrual_base.pot 2013-12-24 15:32:24 +0000
387@@ -0,0 +1,114 @@
388+# Translation of OpenERP Server.
389+# This file contains the translation of the following modules:
390+# * account_cutoff_accrual_base
391+#
392+msgid ""
393+msgstr ""
394+"Project-Id-Version: OpenERP Server 7.0\n"
395+"Report-Msgid-Bugs-To: \n"
396+"POT-Creation-Date: 2013-12-24 15:28+0000\n"
397+"PO-Revision-Date: 2013-12-24 15:28+0000\n"
398+"Last-Translator: <>\n"
399+"Language-Team: \n"
400+"MIME-Version: 1.0\n"
401+"Content-Type: text/plain; charset=UTF-8\n"
402+"Content-Transfer-Encoding: \n"
403+"Plural-Forms: \n"
404+
405+#. module: account_cutoff_accrual_base
406+#: model:ir.model,name:account_cutoff_accrual_base.model_account_cutoff_line
407+msgid "Account Cut-off Line"
408+msgstr ""
409+
410+#. module: account_cutoff_accrual_base
411+#: field:res.company,default_accrued_expense_account_id:0
412+msgid "Default Account for Accrued Expenses"
413+msgstr ""
414+
415+#. module: account_cutoff_accrual_base
416+#: view:account.tax:0
417+msgid "Refunds"
418+msgstr ""
419+
420+#. module: account_cutoff_accrual_base
421+#: help:account.cutoff.line,price_unit:0
422+msgid "Price per unit (discount included)"
423+msgstr ""
424+
425+#. module: account_cutoff_accrual_base
426+#: model:ir.actions.act_window,help:account_cutoff_accrual_base.account_revenue_accrual_action
427+msgid "<p class=\"oe_view_nocontent_create\">\n"
428+" Click to start preparing a new revenue accrual.\n"
429+" </p><p>\n"
430+" This view can be used by accountants in order to collect information about accrued revenue. It then allows to generate the corresponding cut-off journal entry in one click.\n"
431+" </p>\n"
432+" "
433+msgstr ""
434+
435+#. module: account_cutoff_accrual_base
436+#: model:ir.model,name:account_cutoff_accrual_base.model_res_company
437+msgid "Companies"
438+msgstr ""
439+
440+#. module: account_cutoff_accrual_base
441+#: model:ir.actions.act_window,help:account_cutoff_accrual_base.account_expense_accrual_action
442+msgid "<p class=\"oe_view_nocontent_create\">\n"
443+" Click to start preparing a new expense accrual.\n"
444+" </p><p>\n"
445+" This view can be used by accountants in order to collect information about accrued expenses. It then allows to generate the corresponding cut-off journal entry in one click.\n"
446+" </p>\n"
447+" "
448+msgstr ""
449+
450+#. module: account_cutoff_accrual_base
451+#: model:ir.actions.act_window,name:account_cutoff_accrual_base.account_expense_accrual_action
452+#: model:ir.ui.menu,name:account_cutoff_accrual_base.account_expense_accrual_menu
453+msgid "Accrued Expense"
454+msgstr ""
455+
456+#. module: account_cutoff_accrual_base
457+#: model:ir.model,name:account_cutoff_accrual_base.model_account_tax
458+msgid "Tax"
459+msgstr ""
460+
461+#. module: account_cutoff_accrual_base
462+#: model:ir.actions.act_window,name:account_cutoff_accrual_base.account_revenue_accrual_action
463+#: model:ir.ui.menu,name:account_cutoff_accrual_base.account_revenue_accrual_menu
464+msgid "Accrued Revenue"
465+msgstr ""
466+
467+#. module: account_cutoff_accrual_base
468+#: field:account.tax,account_accrued_revenue_id:0
469+msgid "Accrued Revenue Tax Account"
470+msgstr ""
471+
472+#. module: account_cutoff_accrual_base
473+#: field:res.company,default_accrued_revenue_account_id:0
474+msgid "Default Account for Accrued Revenues"
475+msgstr ""
476+
477+#. module: account_cutoff_accrual_base
478+#: view:account.tax:0
479+msgid "Accruals"
480+msgstr ""
481+
482+#. module: account_cutoff_accrual_base
483+#: field:account.cutoff.line,price_unit:0
484+msgid "Unit Price"
485+msgstr ""
486+
487+#. module: account_cutoff_accrual_base
488+#: model:ir.model,name:account_cutoff_accrual_base.model_account_cutoff
489+msgid "Account Cut-off"
490+msgstr ""
491+
492+#. module: account_cutoff_accrual_base
493+#: field:account.tax,account_accrued_expense_id:0
494+msgid "Accrued Expense Tax Account"
495+msgstr ""
496+
497+#. module: account_cutoff_accrual_base
498+#: field:account.cutoff.line,quantity:0
499+msgid "Quantity"
500+msgstr ""
501+
502
503=== added directory 'account_cutoff_accrual_picking'
504=== added file 'account_cutoff_accrual_picking/__init__.py'
505--- account_cutoff_accrual_picking/__init__.py 1970-01-01 00:00:00 +0000
506+++ account_cutoff_accrual_picking/__init__.py 2013-12-24 15:32:24 +0000
507@@ -0,0 +1,23 @@
508+# -*- encoding: utf-8 -*-
509+##############################################################################
510+#
511+# Account Cut-off Accrual Picking module for OpenERP
512+# Copyright (C) 2013 Akretion (http://www.akretion.com)
513+# @author Alexis de Lattre <alexis.delattre@akretion.com>
514+#
515+# This program is free software: you can redistribute it and/or modify
516+# it under the terms of the GNU Affero General Public License as
517+# published by the Free Software Foundation, either version 3 of the
518+# License, or (at your option) any later version.
519+#
520+# This program is distributed in the hope that it will be useful,
521+# but WITHOUT ANY WARRANTY; without even the implied warranty of
522+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
523+# GNU Affero General Public License for more details.
524+#
525+# You should have received a copy of the GNU Affero General Public License
526+# along with this program. If not, see <http://www.gnu.org/licenses/>.
527+#
528+##############################################################################
529+
530+from . import account_cutoff
531
532=== added file 'account_cutoff_accrual_picking/__openerp__.py'
533--- account_cutoff_accrual_picking/__openerp__.py 1970-01-01 00:00:00 +0000
534+++ account_cutoff_accrual_picking/__openerp__.py 2013-12-24 15:32:24 +0000
535@@ -0,0 +1,61 @@
536+# -*- encoding: utf-8 -*-
537+##############################################################################
538+#
539+# Account Cut-off Accrual Picking module for OpenERP
540+# Copyright (C) 2013 Akretion (http://www.akretion.com)
541+# @author Alexis de Lattre <alexis.delattre@akretion.com>
542+#
543+# This program is free software: you can redistribute it and/or modify
544+# it under the terms of the GNU Affero General Public License as
545+# published by the Free Software Foundation, either version 3 of the
546+# License, or (at your option) any later version.
547+#
548+# This program is distributed in the hope that it will be useful,
549+# but WITHOUT ANY WARRANTY; without even the implied warranty of
550+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
551+# GNU Affero General Public License for more details.
552+#
553+# You should have received a copy of the GNU Affero General Public License
554+# along with this program. If not, see <http://www.gnu.org/licenses/>.
555+#
556+##############################################################################
557+
558+
559+{
560+ 'name': 'Account Accrual Picking',
561+ 'version': '0.1',
562+ 'category': 'Accounting & Finance',
563+ 'license': 'AGPL-3',
564+ 'summary': 'Accrued Expense & Accrued Revenue from Pickings',
565+ 'description': """
566+Manage expense and revenue accruals from pickings
567+=================================================
568+
569+This module generates expense and revenue accruals based on the status of pickings.
570+
571+For revenue accruals, OpenERP will take into account all the delivery orders in *Delivered* state that have been shipped before the cut-off date and that have *Invoice Control* = *To Be Invoiced*.
572+
573+For expense accruals, OpenERP will take into account all the incoming shipments in *Received* state that have been received before the cut-off date and that have *Invoice Control* = *To Be Invoiced*.
574+
575+The current code of the module only works when :
576+
577+* on sale orders, the *Create Invoice* field is set to *On Delivery Order* ;
578+* for purchase orders, the *Invoicing Control* field is set to *Based on incoming shipments*.
579+
580+Please contact Alexis de Lattre from Akretion <alexis.delattre@akretion.com> for any help or question about this module.
581+ """,
582+ 'author': 'Akretion',
583+ 'website': 'http://www.akretion.com',
584+ 'depends': ['account_cutoff_accrual_base', 'purchase', 'sale_stock'],
585+ 'data': [
586+ 'account_cutoff_view.xml',
587+ ],
588+ 'images': [
589+ 'images/accrued_expense_draft.jpg',
590+ 'images/accrued_expense_journal_entry.jpg',
591+ 'images/accrued_expense_done.jpg',
592+ ],
593+ 'installable': True,
594+ 'active': False,
595+ 'application': True,
596+}
597
598=== added file 'account_cutoff_accrual_picking/account_cutoff.py'
599--- account_cutoff_accrual_picking/account_cutoff.py 1970-01-01 00:00:00 +0000
600+++ account_cutoff_accrual_picking/account_cutoff.py 2013-12-24 15:32:24 +0000
601@@ -0,0 +1,220 @@
602+# -*- encoding: utf-8 -*-
603+##############################################################################
604+#
605+# Account Cut-off Accrual Picking module for OpenERP
606+# Copyright (C) 2013 Akretion (http://www.akretion.com)
607+# @author Alexis de Lattre <alexis.delattre@akretion.com>
608+#
609+# This program is free software: you can redistribute it and/or modify
610+# it under the terms of the GNU Affero General Public License as
611+# published by the Free Software Foundation, either version 3 of the
612+# License, or (at your option) any later version.
613+#
614+# This program is distributed in the hope that it will be useful,
615+# but WITHOUT ANY WARRANTY; without even the implied warranty of
616+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
617+# GNU Affero General Public License for more details.
618+#
619+# You should have received a copy of the GNU Affero General Public License
620+# along with this program. If not, see <http://www.gnu.org/licenses/>.
621+#
622+##############################################################################
623+
624+from openerp.osv import orm, fields
625+from openerp.tools.translate import _
626+
627+
628+class account_cutoff(orm.Model):
629+ _inherit = 'account.cutoff'
630+
631+ def _prepare_lines_from_picking(
632+ self, cr, uid, ids, cur_cutoff, move_line, account_mapping,
633+ context=None):
634+ tax_obj = self.pool['account.tax']
635+ curr_obj = self.pool['res.currency']
636+ company_currency_id = cur_cutoff['company_currency_id'][0]
637+ assert cur_cutoff['type'] in ('accrued_expense', 'accrued_revenue'),\
638+ "The field 'type' has a wrong value"
639+ if cur_cutoff['type'] == 'accrued_expense':
640+ account_id = move_line.product_id.property_account_expense.id
641+ if not account_id:
642+ account_id = move_line.product_id.categ_id.\
643+ property_account_expense_categ.id
644+ if not account_id:
645+ raise orm.except_orm(
646+ _('Error:'),
647+ _("Missing expense account on product '%s' or on its "
648+ "related product category.")
649+ % (move_line.product_id.name))
650+ currency = move_line.purchase_line_id.order_id.\
651+ pricelist_id.currency_id
652+ analytic_account_id = move_line.purchase_line_id.\
653+ account_analytic_id.id or False
654+ price_unit = move_line.purchase_line_id.price_unit
655+ taxes = move_line.purchase_line_id.taxes_id
656+ partner_id = move_line.purchase_line_id.order_id.partner_id.id
657+ tax_account_field_name = 'account_accrued_expense_id'
658+ tax_account_field_label = 'Accrued Expense Tax Account'
659+
660+ elif cur_cutoff['type'] == 'accrued_revenue':
661+ account_id = move_line.product_id.property_account_income.id
662+ if not account_id:
663+ account_id = move_line.product_id.categ_id.\
664+ property_account_income_categ.id
665+ if not account_id:
666+ raise orm.except_orm(
667+ _('Error:'),
668+ _("Missing income account on product '%s' or on its "
669+ "related product category.")
670+ % (move_line.product_id.name))
671+ currency = move_line.sale_line_id.order_id.pricelist_id.currency_id
672+ analytic_account_id = move_line.sale_line_id.order_id.\
673+ project_id.id or False
674+ discount = move_line.sale_line_id.discount
675+ price_unit = move_line.sale_line_id.price_unit *\
676+ (1-(discount or 0.0)/100.0)
677+ taxes = move_line.sale_line_id.tax_id
678+ partner_id = move_line.sale_line_id.order_id.partner_id.id
679+ tax_account_field_name = 'account_accrued_revenue_id'
680+ tax_account_field_label = 'Accrued Revenue Tax Account'
681+
682+ currency_id = currency.id
683+ quantity = move_line.product_qty
684+ tax_line_ids = []
685+ tax_res = self.pool['account.tax'].compute_all(
686+ cr, uid, taxes, price_unit, quantity,
687+ move_line.product_id.id, partner_id)
688+ amount = tax_res['total'] # =total without taxes
689+ if cur_cutoff['type'] == 'accrued_expense':
690+ amount = amount * -1
691+ context_currency_compute = context.copy()
692+ context_currency_compute['date'] = cur_cutoff['cutoff_date']
693+ for tax_line in tax_res['taxes']:
694+ tax_read = tax_obj.read(
695+ cr, uid, tax_line['id'],
696+ [tax_account_field_name, 'name'], context=context)
697+ tax_accrual_account_id = tax_read[tax_account_field_name]
698+ if not tax_accrual_account_id:
699+ raise orm.except_orm(
700+ _('Error:'),
701+ _("Missing '%s' on tax '%s'.")
702+ % (tax_account_field_label, tax_read['name']))
703+ else:
704+ tax_accrual_account_id = tax_accrual_account_id[0]
705+ if cur_cutoff['type'] == 'accrued_expense':
706+ tax_line['amount'] = tax_line['amount'] * -1
707+ if company_currency_id != currency_id:
708+ tax_accrual_amount = curr_obj.compute(
709+ cr, uid, currency_id, company_currency_id,
710+ tax_line['amount'],
711+ context=context_currency_compute)
712+ else:
713+ tax_accrual_amount = tax_line['amount']
714+ tax_line_ids.append((0, 0, {
715+ 'tax_id': tax_line['id'],
716+ 'base': curr_obj.round(
717+ cr, uid, currency,
718+ tax_line['price_unit'] * quantity),
719+ 'amount': tax_line['amount'],
720+ 'sequence': tax_line['sequence'],
721+ 'cutoff_account_id': tax_accrual_account_id,
722+ 'cutoff_amount': tax_accrual_amount,
723+ 'analytic_account_id':
724+ tax_line['account_analytic_collected_id'],
725+ # account_analytic_collected_id is for
726+ # invoices IN and OUT
727+ }))
728+ if company_currency_id != currency_id:
729+ amount_company_currency = curr_obj.compute(
730+ cr, uid, currency_id, company_currency_id, amount,
731+ context=context_currency_compute)
732+ else:
733+ amount_company_currency = amount
734+
735+ # we use account mapping here
736+ if account_id in account_mapping:
737+ accrual_account_id = account_mapping[account_id]
738+ else:
739+ accrual_account_id = account_id
740+ res = {
741+ 'parent_id': ids[0],
742+ 'partner_id': partner_id,
743+ 'stock_move_id': move_line.id,
744+ 'name': move_line.name,
745+ 'account_id': account_id,
746+ 'cutoff_account_id': accrual_account_id,
747+ 'analytic_account_id': analytic_account_id,
748+ 'currency_id': currency_id,
749+ 'quantity': quantity,
750+ 'price_unit': price_unit,
751+ 'tax_ids': [(6, 0, [tax.id for tax in taxes])],
752+ 'amount': amount,
753+ 'cutoff_amount': amount_company_currency,
754+ 'tax_line_ids': tax_line_ids,
755+ }
756+ return res
757+
758+ def get_lines_from_picking(self, cr, uid, ids, context=None):
759+ assert len(ids) == 1, \
760+ 'This function should only be used for a single id at a time'
761+ pick_obj = self.pool['stock.picking']
762+ line_obj = self.pool['account.cutoff.line']
763+ mapping_obj = self.pool['account.cutoff.mapping']
764+
765+ cur_cutoff = self.read(cr, uid, ids[0], [
766+ 'line_ids', 'type', 'cutoff_date', 'company_id',
767+ 'company_currency_id',
768+ ],
769+ context=context)
770+ # delete existing lines based on pickings
771+ to_delete_line_ids = line_obj.search(
772+ cr, uid, [
773+ ('parent_id', '=', cur_cutoff['id']),
774+ ('stock_move_id', '!=', False)
775+ ],
776+ context=context)
777+ if to_delete_line_ids:
778+ line_obj.unlink(cr, uid, to_delete_line_ids, context=context)
779+ pick_type_map = {
780+ 'accrued_revenue': 'out',
781+ 'accrued_expense': 'in',
782+ }
783+ assert cur_cutoff['type'] in pick_type_map, \
784+ "cur_cutoff['type'] should be in pick_type_map.keys()"
785+ pick_ids = pick_obj.search(cr, uid, [
786+ ('type', '=', pick_type_map[cur_cutoff['type']]),
787+ ('state', '=', 'done'),
788+ ('invoice_state', '=', '2binvoiced'),
789+ ('date_done', '<=', cur_cutoff['cutoff_date'])
790+ ], context=context)
791+ #print "pick_ids=", pick_ids
792+ # Create account mapping dict
793+ account_mapping = mapping_obj._get_mapping_dict(
794+ cr, uid, cur_cutoff['company_id'][0], cur_cutoff['type'],
795+ context=context)
796+ for picking in pick_obj.browse(cr, uid, pick_ids, context=context):
797+ for move_line in picking.move_lines:
798+ line_obj.create(
799+ cr, uid, self._prepare_lines_from_picking(
800+ cr, uid, ids, cur_cutoff, move_line,
801+ account_mapping, context=context),
802+ context=context)
803+ return True
804+
805+
806+class account_cutoff_line(orm.Model):
807+ _inherit = 'account.cutoff.line'
808+
809+ _columns = {
810+ 'stock_move_id': fields.many2one(
811+ 'stock.move', 'Stock Move', readonly=True),
812+ 'product_id': fields.related(
813+ 'stock_move_id', 'product_id', type='many2one',
814+ relation='product.product', string='Product', readonly=True),
815+ 'picking_id': fields.related(
816+ 'stock_move_id', 'picking_id', type='many2one',
817+ relation='stock.picking', string='Picking', readonly=True),
818+ 'picking_date_done': fields.related(
819+ 'picking_id', 'date_done', type='date',
820+ string='Date Done of the Picking', readonly=True),
821+ }
822
823=== added file 'account_cutoff_accrual_picking/account_cutoff_view.xml'
824--- account_cutoff_accrual_picking/account_cutoff_view.xml 1970-01-01 00:00:00 +0000
825+++ account_cutoff_accrual_picking/account_cutoff_view.xml 2013-12-24 15:32:24 +0000
826@@ -0,0 +1,54 @@
827+<?xml version="1.0" encoding="utf-8"?>
828+
829+<!--
830+ Copyright (C) 2013 Akretion (http://www.akretion.com/)
831+ @author Alexis de Lattre <alexis.delattre@akretion.com>
832+ The licence is in the file __openerp__.py
833+-->
834+
835+<openerp>
836+<data>
837+
838+<!-- Form view -->
839+<record id="account_cutoff_form" model="ir.ui.view">
840+ <field name="name">account.cutoff.picking.form</field>
841+ <field name="model">account.cutoff</field>
842+ <field name="inherit_id" ref="account_cutoff_base.account_cutoff_form"/>
843+ <field name="arch" type="xml">
844+ <button name="back2draft" position="after">
845+ <button class="oe_highlight" name="get_lines_from_picking" string="Re-Generate Lines from Picking" type="object" states="draft" invisible="'accrued' not in context.get('type', '-')"/>
846+ </button>
847+ </field>
848+</record>
849+
850+<!-- Form view for lines -->
851+<record id="account_cutoff_line_form" model="ir.ui.view">
852+ <field name="name">account.cutoff.line.picking.form</field>
853+ <field name="model">account.cutoff.line</field>
854+ <field name="inherit_id" ref="account_cutoff_base.account_cutoff_line_form"/>
855+ <field name="arch" type="xml">
856+ <field name="parent_id" position="after">
857+ <field name="stock_move_id" invisible="'accrued' not in context.get('type', '-')"/>
858+ <field name="product_id" invisible="'accrued' not in context.get('type', '-')" />
859+ <field name="picking_id" invisible="'accrued' not in context.get('type', '-')"/>
860+ <field name="picking_date_done" invisible="'accrued' not in context.get('type', '-')"/>
861+ </field>
862+ </field>
863+</record>
864+
865+<!-- Tree view for lines -->
866+<record id="account_cutoff_line_tree" model="ir.ui.view">
867+ <field name="name">account.cutoff.line.picking.tree</field>
868+ <field name="model">account.cutoff.line</field>
869+ <field name="inherit_id" ref="account_cutoff_base.account_cutoff_line_tree"/>
870+ <field name="arch" type="xml">
871+ <field name="parent_id" position="after">
872+ <field name="stock_move_id" invisible="'accrued' not in context.get('type', '-')"/>
873+ <field name="picking_date_done" invisible="'accrued' not in context.get('type', '-')"/>
874+ </field>
875+ </field>
876+</record>
877+
878+
879+</data>
880+</openerp>
881
882=== added directory 'account_cutoff_accrual_picking/i18n'
883=== added file 'account_cutoff_accrual_picking/i18n/account_cutoff_accrual_picking.pot'
884--- account_cutoff_accrual_picking/i18n/account_cutoff_accrual_picking.pot 1970-01-01 00:00:00 +0000
885+++ account_cutoff_accrual_picking/i18n/account_cutoff_accrual_picking.pot 2013-12-24 15:32:24 +0000
886@@ -0,0 +1,78 @@
887+# Translation of OpenERP Server.
888+# This file contains the translation of the following modules:
889+# * account_cutoff_accrual_picking
890+#
891+msgid ""
892+msgstr ""
893+"Project-Id-Version: OpenERP Server 7.0\n"
894+"Report-Msgid-Bugs-To: \n"
895+"POT-Creation-Date: 2013-12-24 15:27+0000\n"
896+"PO-Revision-Date: 2013-12-24 15:27+0000\n"
897+"Last-Translator: <>\n"
898+"Language-Team: \n"
899+"MIME-Version: 1.0\n"
900+"Content-Type: text/plain; charset=UTF-8\n"
901+"Content-Transfer-Encoding: \n"
902+"Plural-Forms: \n"
903+
904+#. module: account_cutoff_accrual_picking
905+#: model:ir.model,name:account_cutoff_accrual_picking.model_account_cutoff_line
906+msgid "Account Cut-off Line"
907+msgstr ""
908+
909+#. module: account_cutoff_accrual_picking
910+#: field:account.cutoff.line,product_id:0
911+msgid "Product"
912+msgstr ""
913+
914+#. module: account_cutoff_accrual_picking
915+#: field:account.cutoff.line,stock_move_id:0
916+msgid "Stock Move"
917+msgstr ""
918+
919+#. module: account_cutoff_accrual_picking
920+#: model:ir.model,name:account_cutoff_accrual_picking.model_account_cutoff
921+msgid "Account Cut-off"
922+msgstr ""
923+
924+#. module: account_cutoff_accrual_picking
925+#: view:account.cutoff:0
926+msgid "Re-Generate Lines from Picking"
927+msgstr ""
928+
929+#. module: account_cutoff_accrual_picking
930+#: code:addons/account_cutoff_accrual_picking/account_cutoff.py:67
931+#, python-format
932+msgid "Missing income account on product '%s' or on its related product category."
933+msgstr ""
934+
935+#. module: account_cutoff_accrual_picking
936+#: code:addons/account_cutoff_accrual_picking/account_cutoff.py:100
937+#, python-format
938+msgid "Missing '%s' on tax '%s'."
939+msgstr ""
940+
941+#. module: account_cutoff_accrual_picking
942+#: code:addons/account_cutoff_accrual_picking/account_cutoff.py:46
943+#, python-format
944+msgid "Missing expense account on product '%s' or on its related product category."
945+msgstr ""
946+
947+#. module: account_cutoff_accrual_picking
948+#: field:account.cutoff.line,picking_id:0
949+msgid "Picking"
950+msgstr ""
951+
952+#. module: account_cutoff_accrual_picking
953+#: field:account.cutoff.line,picking_date_done:0
954+msgid "Date Done of the Picking"
955+msgstr ""
956+
957+#. module: account_cutoff_accrual_picking
958+#: code:addons/account_cutoff_accrual_picking/account_cutoff.py:45
959+#: code:addons/account_cutoff_accrual_picking/account_cutoff.py:66
960+#: code:addons/account_cutoff_accrual_picking/account_cutoff.py:99
961+#, python-format
962+msgid "Error:"
963+msgstr ""
964+
965
966=== added directory 'account_cutoff_accrual_picking/images'
967=== added file 'account_cutoff_accrual_picking/images/accrued_expense_done.jpg'
968Binary files account_cutoff_accrual_picking/images/accrued_expense_done.jpg 1970-01-01 00:00:00 +0000 and account_cutoff_accrual_picking/images/accrued_expense_done.jpg 2013-12-24 15:32:24 +0000 differ
969=== added file 'account_cutoff_accrual_picking/images/accrued_expense_draft.jpg'
970Binary files account_cutoff_accrual_picking/images/accrued_expense_draft.jpg 1970-01-01 00:00:00 +0000 and account_cutoff_accrual_picking/images/accrued_expense_draft.jpg 2013-12-24 15:32:24 +0000 differ
971=== added file 'account_cutoff_accrual_picking/images/accrued_expense_journal_entry.jpg'
972Binary files account_cutoff_accrual_picking/images/accrued_expense_journal_entry.jpg 1970-01-01 00:00:00 +0000 and account_cutoff_accrual_picking/images/accrued_expense_journal_entry.jpg 2013-12-24 15:32:24 +0000 differ
973=== added directory 'account_cutoff_accrual_picking/static'
974=== added directory 'account_cutoff_accrual_picking/static/src'
975=== added directory 'account_cutoff_accrual_picking/static/src/img'
976=== added file 'account_cutoff_accrual_picking/static/src/img/icon.png'
977Binary files account_cutoff_accrual_picking/static/src/img/icon.png 1970-01-01 00:00:00 +0000 and account_cutoff_accrual_picking/static/src/img/icon.png 2013-12-24 15:32:24 +0000 differ
978=== added directory 'account_cutoff_base'
979=== added file 'account_cutoff_base/__init__.py'
980--- account_cutoff_base/__init__.py 1970-01-01 00:00:00 +0000
981+++ account_cutoff_base/__init__.py 2013-12-24 15:32:24 +0000
982@@ -0,0 +1,24 @@
983+# -*- encoding: utf-8 -*-
984+##############################################################################
985+#
986+# Account Cut-off Base module for OpenERP
987+# Copyright (C) 2013 Akretion (http://www.akretion.com)
988+# @author Alexis de Lattre <alexis.delattre@akretion.com>
989+#
990+# This program is free software: you can redistribute it and/or modify
991+# it under the terms of the GNU Affero General Public License as
992+# published by the Free Software Foundation, either version 3 of the
993+# License, or (at your option) any later version.
994+#
995+# This program is distributed in the hope that it will be useful,
996+# but WITHOUT ANY WARRANTY; without even the implied warranty of
997+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
998+# GNU Affero General Public License for more details.
999+#
1000+# You should have received a copy of the GNU Affero General Public License
1001+# along with this program. If not, see <http://www.gnu.org/licenses/>.
1002+#
1003+##############################################################################
1004+
1005+from . import account_cutoff
1006+from . import company
1007
1008=== added file 'account_cutoff_base/__openerp__.py'
1009--- account_cutoff_base/__openerp__.py 1970-01-01 00:00:00 +0000
1010+++ account_cutoff_base/__openerp__.py 2013-12-24 15:32:24 +0000
1011@@ -0,0 +1,47 @@
1012+# -*- encoding: utf-8 -*-
1013+##############################################################################
1014+#
1015+# Account Cut-off Base module for OpenERP
1016+# Copyright (C) 2013 Akretion (http://www.akretion.com)
1017+# @author Alexis de Lattre <alexis.delattre@akretion.com>
1018+#
1019+# This program is free software: you can redistribute it and/or modify
1020+# it under the terms of the GNU Affero General Public License as
1021+# published by the Free Software Foundation, either version 3 of the
1022+# License, or (at your option) any later version.
1023+#
1024+# This program is distributed in the hope that it will be useful,
1025+# but WITHOUT ANY WARRANTY; without even the implied warranty of
1026+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1027+# GNU Affero General Public License for more details.
1028+#
1029+# You should have received a copy of the GNU Affero General Public License
1030+# along with this program. If not, see <http://www.gnu.org/licenses/>.
1031+#
1032+##############################################################################
1033+
1034+
1035+{
1036+ 'name': 'Account Cut-off Base',
1037+ 'version': '0.1',
1038+ 'category': 'Accounting & Finance',
1039+ 'license': 'AGPL-3',
1040+ 'summary': 'Base module for Account Cut-offs',
1041+ 'description': """This module contains objets, fields and menu entries that are used by other cut-off modules. So you need to install other cut-off modules to get the additionnal functionalities :
1042+
1043+* the module *account_cutoff_prepaid* will manage prepaid cut-offs based on start date and end date,
1044+* the module *account_cutoff_accrual_picking* will manage the accruals based on the status of the pickings.
1045+
1046+Please contact Alexis de Lattre from Akretion <alexis.delattre@akretion.com> for any help or question about this module.
1047+ """,
1048+ 'author': 'Akretion',
1049+ 'website': 'http://www.akretion.com',
1050+ 'depends': ['account_accountant'],
1051+ 'data': [
1052+ 'company_view.xml',
1053+ 'account_cutoff_view.xml',
1054+ 'security/ir.model.access.csv',
1055+ ],
1056+ 'installable': True,
1057+ 'active': False,
1058+}
1059
1060=== added file 'account_cutoff_base/account_cutoff.py'
1061--- account_cutoff_base/account_cutoff.py 1970-01-01 00:00:00 +0000
1062+++ account_cutoff_base/account_cutoff.py 2013-12-24 15:32:24 +0000
1063@@ -0,0 +1,445 @@
1064+# -*- encoding: utf-8 -*-
1065+##############################################################################
1066+#
1067+# Account Cut-off Base module for OpenERP
1068+# Copyright (C) 2013 Akretion (http://www.akretion.com)
1069+# @author Alexis de Lattre <alexis.delattre@akretion.com>
1070+#
1071+# This program is free software: you can redistribute it and/or modify
1072+# it under the terms of the GNU Affero General Public License as
1073+# published by the Free Software Foundation, either version 3 of the
1074+# License, or (at your option) any later version.
1075+#
1076+# This program is distributed in the hope that it will be useful,
1077+# but WITHOUT ANY WARRANTY; without even the implied warranty of
1078+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1079+# GNU Affero General Public License for more details.
1080+#
1081+# You should have received a copy of the GNU Affero General Public License
1082+# along with this program. If not, see <http://www.gnu.org/licenses/>.
1083+#
1084+##############################################################################
1085+
1086+from openerp.osv import orm, fields
1087+import openerp.addons.decimal_precision as dp
1088+from openerp.tools.translate import _
1089+from datetime import datetime
1090+
1091+
1092+class account_cutoff(orm.Model):
1093+ _name = 'account.cutoff'
1094+ _rec_name = 'cutoff_date'
1095+ _order = 'cutoff_date desc'
1096+ _inherit = ['mail.thread']
1097+ _description = 'Account Cut-off'
1098+ _track = {
1099+ 'state': {
1100+ 'account_cutoff_base.cutoff_done':
1101+ lambda self, cr, uid, obj, ctx=None: obj['state'] == 'done',
1102+ }
1103+ }
1104+
1105+ def copy(self, cr, uid, id, default=None, context=None):
1106+ if default is None:
1107+ default = {}
1108+ default.update({
1109+ 'cutoff_date': '%d-12-31' % datetime.today().year,
1110+ 'move_id': False,
1111+ 'state': 'draft',
1112+ 'line_ids': False,
1113+ })
1114+ return super(account_cutoff, self).copy(
1115+ cr, uid, id, default=default, context=context)
1116+
1117+ def _compute_total_cutoff(self, cr, uid, ids, name, arg, context=None):
1118+ res = {}
1119+ for cutoff in self.browse(cr, uid, ids, context=context):
1120+ res[cutoff.id] = 0
1121+ for line in cutoff.line_ids:
1122+ res[cutoff.id] += line.cutoff_amount
1123+ return res
1124+
1125+ _columns = {
1126+ 'cutoff_date': fields.date(
1127+ 'Cut-off Date', required=True, readonly=True,
1128+ states={'draft': [('readonly', False)]},
1129+ track_visibility='always'),
1130+ 'type': fields.selection([
1131+ ('accrued_revenue', 'Accrued Revenue'),
1132+ ('accrued_expense', 'Accrued Expense'),
1133+ ('prepaid_revenue', 'Prepaid Revenue'),
1134+ ('prepaid_expense', 'Prepaid Expense'),
1135+ ], 'Type', required=True, readonly=True,
1136+ states={'draft': [('readonly', False)]}),
1137+ 'move_id': fields.many2one(
1138+ 'account.move', 'Cut-off Journal Entry', readonly=True),
1139+ 'move_label': fields.char(
1140+ 'Label of the Cut-off Journal Entry',
1141+ size=64, required=True, readonly=True,
1142+ states={'draft': [('readonly', False)]},
1143+ help="This label will be written in the 'Name' field of the "
1144+ "Cut-off Account Move Lines and in the 'Reference' field of "
1145+ "the Cut-off Account Move."),
1146+ 'cutoff_account_id': fields.many2one(
1147+ 'account.account', 'Cut-off Account',
1148+ domain=[('type', '<>', 'view'), ('type', '<>', 'closed')],
1149+ required=True, readonly=True,
1150+ states={'draft': [('readonly', False)]}),
1151+ 'cutoff_journal_id': fields.many2one(
1152+ 'account.journal', 'Cut-off Account Journal', required=True,
1153+ readonly=True, states={'draft': [('readonly', False)]}),
1154+ 'total_cutoff_amount': fields.function(
1155+ _compute_total_cutoff, type='float', string="Total Cut-off Amount",
1156+ readonly=True, track_visibility='always'),
1157+ 'company_id': fields.many2one(
1158+ 'res.company', 'Company', required=True, readonly=True,
1159+ states={'draft': [('readonly', False)]}),
1160+ 'company_currency_id': fields.related(
1161+ 'company_id', 'currency_id', readonly=True, type='many2one',
1162+ relation='res.currency', string='Company Currency'),
1163+ 'line_ids': fields.one2many(
1164+ 'account.cutoff.line', 'parent_id', 'Cut-off Lines', readonly=True,
1165+ states={'draft': [('readonly', False)]}),
1166+ 'state': fields.selection([
1167+ ('draft', 'Draft'),
1168+ ('done', 'Done'),
1169+ ],
1170+ 'State', select=True, readonly=True, track_visibility='onchange',
1171+ help="State of the cutoff. When the Journal Entry is created, "
1172+ "the state is set to 'Done' and the fields become read-only."),
1173+ }
1174+
1175+ def _get_default_journal(self, cr, uid, context=None):
1176+ cur_user = self.pool['res.users'].browse(cr, uid, uid, context=context)
1177+ return cur_user.company_id.default_cutoff_journal_id.id or None
1178+
1179+ def _default_move_label(self, cr, uid, context=None):
1180+ if context is None:
1181+ context = {}
1182+ type = context.get('type')
1183+ cutoff_date = context.get('cutoff_date')
1184+ if cutoff_date:
1185+ cutoff_date_label = ' dated %s' % cutoff_date
1186+ else:
1187+ cutoff_date_label = ''
1188+ label = ''
1189+ if type == 'accrued_expense':
1190+ label = _('Accrued Expense%s') % cutoff_date_label
1191+ elif type == 'accrued_revenue':
1192+ label = _('Accrued Revenue%s') % cutoff_date_label
1193+ elif type == 'prepaid_revenue':
1194+ label = _('Prepaid Revenue%s') % cutoff_date_label
1195+ elif type == 'prepaid_expense':
1196+ label = _('Prepaid Expense%s') % cutoff_date_label
1197+ return label
1198+
1199+ def _default_type(self, cr, uid, context=None):
1200+ if context is None:
1201+ context = {}
1202+ return context.get('type')
1203+
1204+ def _inherit_default_cutoff_account_id(self, cr, uid, context=None):
1205+ '''Function designed to be inherited by other cutoff modules'''
1206+ return None
1207+
1208+ def _default_cutoff_account_id(self, cr, uid, context=None):
1209+ '''This function can't be inherited, so we use a second function'''
1210+ return self._inherit_default_cutoff_account_id(
1211+ cr, uid, context=context)
1212+
1213+ _defaults = {
1214+ 'state': 'draft',
1215+ 'company_id': lambda self, cr, uid, context:
1216+ self.pool['res.users'].browse(
1217+ cr, uid, uid, context=context).company_id.id,
1218+ 'cutoff_journal_id': _get_default_journal,
1219+ 'move_label': _default_move_label,
1220+ 'type': _default_type,
1221+ 'cutoff_account_id': _default_cutoff_account_id,
1222+ }
1223+
1224+ _sql_constraints = [(
1225+ 'date_type_company_uniq',
1226+ 'unique(cutoff_date, company_id, type)',
1227+ 'A cutoff of the same type already exists with this cut-off date !'
1228+ )]
1229+
1230+ def cutoff_date_onchange(
1231+ self, cr, uid, ids, type, cutoff_date, move_label):
1232+ res = {'value': {}}
1233+ if type and cutoff_date:
1234+ context = {'type': type, 'cutoff_date': cutoff_date}
1235+ res['value']['move_label'] = self._default_move_label(
1236+ cr, uid, context=context)
1237+ return res
1238+
1239+ def back2draft(self, cr, uid, ids, context=None):
1240+ assert len(ids) == 1,\
1241+ 'This function should only be used for a single id at a time'
1242+ cur_cutoff = self.browse(cr, uid, ids[0], context=context)
1243+ if cur_cutoff.move_id:
1244+ self.pool['account.move'].unlink(
1245+ cr, uid, [cur_cutoff.move_id.id], context=context)
1246+ self.write(cr, uid, ids[0], {'state': 'draft'}, context=context)
1247+ return True
1248+
1249+ def _prepare_move(self, cr, uid, cur_cutoff, to_provision, context=None):
1250+ if context is None:
1251+ context = {}
1252+ movelines_to_create = []
1253+ amount_total = 0
1254+ move_label = cur_cutoff.move_label
1255+ for (cutoff_account_id, analytic_account_id), amount in \
1256+ to_provision.items():
1257+ movelines_to_create.append((0, 0, {
1258+ 'account_id': cutoff_account_id,
1259+ 'name': move_label,
1260+ 'debit': amount < 0 and amount * -1 or 0,
1261+ 'credit': amount >= 0 and amount or 0,
1262+ 'analytic_account_id': analytic_account_id,
1263+ }))
1264+ amount_total += amount
1265+
1266+ # add contre-partie
1267+ counterpart_amount = amount_total * -1
1268+ movelines_to_create.append((0, 0, {
1269+ 'account_id': cur_cutoff.cutoff_account_id.id,
1270+ 'debit': counterpart_amount < 0 and counterpart_amount * -1 or 0,
1271+ 'credit': counterpart_amount >= 0 and counterpart_amount or 0,
1272+ 'name': move_label,
1273+ 'analytic_account_id': False,
1274+ }))
1275+
1276+ # Select period
1277+ local_ctx = context.copy()
1278+ local_ctx['account_period_prefer_normal'] = True
1279+ period_search = self.pool['account.period'].find(
1280+ cr, uid, cur_cutoff.cutoff_date, context=local_ctx)
1281+ if len(period_search) != 1:
1282+ raise orm.except_orm(
1283+ 'Error:', "No matching period for date '%s'"
1284+ % cur_cutoff.cutoff_date)
1285+ period_id = period_search[0]
1286+
1287+ res = {
1288+ 'journal_id': cur_cutoff.cutoff_journal_id.id,
1289+ 'date': cur_cutoff.cutoff_date,
1290+ 'period_id': period_id,
1291+ 'ref': move_label,
1292+ 'line_id': movelines_to_create,
1293+ }
1294+ return res
1295+
1296+ def create_move(self, cr, uid, ids, context=None):
1297+ assert len(ids) == 1, \
1298+ 'This function should only be used for a single id at a time'
1299+ move_obj = self.pool['account.move']
1300+ cur_cutoff = self.browse(cr, uid, ids[0], context=context)
1301+ if cur_cutoff.move_id:
1302+ raise orm.except_orm(
1303+ _('Error:'),
1304+ _("The Cut-off Journal Entry already exists. You should "
1305+ "delete it before running this function."))
1306+ if not cur_cutoff.line_ids:
1307+ raise orm.except_orm(
1308+ _('Error:'),
1309+ _("There are no lines on this Cut-off, so we can't create "
1310+ "a Journal Entry."))
1311+ to_provision = {}
1312+ # key = (cutoff_account_id, analytic_account_id)
1313+ # value = amount
1314+ for line in cur_cutoff.line_ids:
1315+ # if it is already present
1316+ if (
1317+ line.cutoff_account_id.id,
1318+ line.analytic_account_id.id or False
1319+ ) in to_provision:
1320+ to_provision[(
1321+ line.cutoff_account_id.id,
1322+ line.analytic_account_id.id or False
1323+ )] += line.cutoff_amount
1324+ else:
1325+ # if not already present
1326+ to_provision[(
1327+ line.cutoff_account_id.id,
1328+ line.analytic_account_id.id or False
1329+ )] = line.cutoff_amount
1330+ # Same for tax lines
1331+ for tax_line in line.tax_line_ids:
1332+ if (
1333+ tax_line.cutoff_account_id.id,
1334+ tax_line.analytic_account_id.id or False
1335+ ) in to_provision:
1336+ to_provision[(
1337+ tax_line.cutoff_account_id.id,
1338+ tax_line.analytic_account_id.id or False
1339+ )] += tax_line.cutoff_amount
1340+ else:
1341+ to_provision[(
1342+ tax_line.cutoff_account_id.id,
1343+ tax_line.analytic_account_id.id or False
1344+ )] = tax_line.cutoff_amount
1345+
1346+ vals = self._prepare_move(
1347+ cr, uid, cur_cutoff, to_provision, context=context)
1348+ move_id = move_obj.create(cr, uid, vals, context=context)
1349+ move_obj.validate(cr, uid, [move_id], context=context)
1350+ self.write(cr, uid, ids[0], {
1351+ 'move_id': move_id,
1352+ 'state': 'done',
1353+ }, context=context)
1354+
1355+ action = {
1356+ 'name': 'Cut-off Account Move',
1357+ 'view_type': 'form',
1358+ 'view_mode': 'form,tree',
1359+ 'res_id': move_id,
1360+ 'view_id': False,
1361+ 'res_model': 'account.move',
1362+ 'type': 'ir.actions.act_window',
1363+ 'nodestroy': False,
1364+ 'target': 'current',
1365+ }
1366+ return action
1367+
1368+
1369+class account_cutoff_line(orm.Model):
1370+ _name = 'account.cutoff.line'
1371+ _description = 'Account Cut-off Line'
1372+
1373+ _columns = {
1374+ 'parent_id': fields.many2one(
1375+ 'account.cutoff', 'Cut-off', ondelete='cascade'),
1376+ 'name': fields.char('Description', size=64),
1377+ 'company_currency_id': fields.related(
1378+ 'parent_id', 'company_currency_id', type='many2one',
1379+ relation='res.currency', string="Company Currency", readonly=True),
1380+ 'partner_id': fields.many2one('res.partner', 'Partner', readonly=True),
1381+ 'account_id': fields.many2one(
1382+ 'account.account', 'Account',
1383+ domain=[('type', '<>', 'view'), ('type', '<>', 'closed')],
1384+ required=True, readonly=True),
1385+ 'cutoff_account_id': fields.many2one(
1386+ 'account.account', 'Cut-off Account',
1387+ domain=[('type', '<>', 'view'), ('type', '<>', 'closed')],
1388+ required=True, readonly=True),
1389+ 'cutoff_account_code': fields.related(
1390+ 'cutoff_account_id', 'code', type='char',
1391+ string='Cut-off Account Code', readonly=True),
1392+ 'analytic_account_id': fields.many2one(
1393+ 'account.analytic.account', 'Analytic Account',
1394+ domain=[('type', 'not in', ('view', 'template'))],
1395+ readonly=True),
1396+ 'analytic_account_code': fields.related(
1397+ 'analytic_account_id', 'code', type='char',
1398+ string='Analytic Account Code', readonly=True),
1399+ 'currency_id': fields.many2one(
1400+ 'res.currency', 'Amount Currency', readonly=True,
1401+ help="Currency of the 'Amount' field."),
1402+ 'amount': fields.float(
1403+ 'Amount', digits_compute=dp.get_precision('Account'),
1404+ readonly=True,
1405+ help="Amount that is used as base to compute the Cut-off Amount. "
1406+ "This Amount is in the 'Amount Currency', which may be different "
1407+ "from the 'Company Currency'."),
1408+ 'cutoff_amount': fields.float(
1409+ 'Cut-off Amount', digits_compute=dp.get_precision('Account'),
1410+ readonly=True,
1411+ help="Cut-off Amount without taxes in the Company Currency."),
1412+ 'tax_ids': fields.many2many(
1413+ 'account.tax', id1='cutoff_line_id', id2='tax_id', string='Taxes',
1414+ readonly=True),
1415+ 'tax_line_ids': fields.one2many(
1416+ 'account.cutoff.tax.line', 'parent_id', 'Cut-off Tax Lines',
1417+ readonly=True),
1418+ }
1419+
1420+
1421+class account_cutoff_tax_line(orm.Model):
1422+ _name = 'account.cutoff.tax.line'
1423+ _description = 'Account Cut-off Tax Line'
1424+
1425+ _columns = {
1426+ 'parent_id': fields.many2one(
1427+ 'account.cutoff.line', 'Account Cut-off Line',
1428+ ondelete='cascade', required=True),
1429+ 'tax_id': fields.many2one('account.tax', 'Tax', required=True),
1430+ 'cutoff_account_id': fields.many2one(
1431+ 'account.account', 'Cut-off Account',
1432+ domain=[('type', '<>', 'view'), ('type', '<>', 'closed')],
1433+ required=True, readonly=True),
1434+ 'analytic_account_id': fields.many2one(
1435+ 'account.analytic.account', 'Analytic Account',
1436+ domain=[('type', 'not in', ('view', 'template'))],
1437+ readonly=True),
1438+ 'base': fields.float(
1439+ 'Base', digits_compute=dp.get_precision('Account'),
1440+ readonly=True, help="Base Amount in the currency of the PO."),
1441+ 'amount': fields.float(
1442+ 'Tax Amount', digits_compute=dp.get_precision('Account'),
1443+ readonly=True, help='Tax Amount in the currency of the PO.'),
1444+ 'sequence': fields.integer('Sequence', readonly=True),
1445+ 'cutoff_amount': fields.float(
1446+ 'Cut-off Tax Amount', digits_compute=dp.get_precision('Account'),
1447+ readonly=True,
1448+ help="Tax Cut-off Amount in the company currency."),
1449+ 'currency_id': fields.related(
1450+ 'parent_id', 'currency_id', type='many2one',
1451+ relation='res.currency', string='Currency', readonly=True),
1452+ 'company_currency_id': fields.related(
1453+ 'parent_id', 'company_currency_id',
1454+ type='many2one', relation='res.currency',
1455+ string="Company Currency", readonly=True),
1456+ }
1457+
1458+
1459+class account_cutoff_mapping(orm.Model):
1460+ _name = 'account.cutoff.mapping'
1461+ _description = 'Account Cut-off Mapping'
1462+ _rec_name = 'account_id'
1463+
1464+ _columns = {
1465+ 'company_id': fields.many2one('res.company', 'Company', required=True),
1466+ 'account_id': fields.many2one(
1467+ 'account.account', 'Regular Account',
1468+ domain=[('type', '<>', 'view'), ('type', '<>', 'closed')],
1469+ required=True),
1470+ 'cutoff_account_id': fields.many2one(
1471+ 'account.account', 'Cut-off Account',
1472+ domain=[('type', '<>', 'view'), ('type', '<>', 'closed')],
1473+ required=True),
1474+ 'cutoff_type': fields.selection([
1475+ ('all', 'All Cut-off Types'),
1476+ ('accrued_revenue', 'Accrued Revenue'),
1477+ ('accrued_expense', 'Accrued Expense'),
1478+ ('prepaid_revenue', 'Prepaid Revenue'),
1479+ ('prepaid_expense', 'Prepaid Expense'),
1480+ ], 'Cut-off Type', required=True),
1481+ }
1482+
1483+ _defaults = {
1484+ 'company_id': lambda self, cr, uid, context:
1485+ self.pool['res.users'].browse(
1486+ cr, uid, uid, context=context).company_id.id,
1487+ }
1488+
1489+ def _get_mapping_dict(
1490+ self, cr, uid, company_id, cutoff_type='all', context=None):
1491+ '''return a dict with:
1492+ key = ID of account,
1493+ value = ID of cutoff_account'''
1494+ if cutoff_type == 'all':
1495+ cutoff_type_filter = ('all')
1496+ else:
1497+ cutoff_type_filter = ('all', cutoff_type)
1498+ mapping_ids = self.search(
1499+ cr, uid, [
1500+ ('company_id', '=', company_id),
1501+ ('cutoff_type', 'in', cutoff_type_filter),
1502+ ],
1503+ context=context)
1504+ mapping_read = self.read(cr, uid, mapping_ids, context=context)
1505+ mapping = {}
1506+ for item in mapping_read:
1507+ mapping[item['account_id'][0]] = item['cutoff_account_id'][0]
1508+ return mapping
1509
1510=== added file 'account_cutoff_base/account_cutoff_view.xml'
1511--- account_cutoff_base/account_cutoff_view.xml 1970-01-01 00:00:00 +0000
1512+++ account_cutoff_base/account_cutoff_view.xml 2013-12-24 15:32:24 +0000
1513@@ -0,0 +1,240 @@
1514+<?xml version="1.0" encoding="utf-8"?>
1515+
1516+<!--
1517+ Copyright (C) 2013 Akretion (http://www.akretion.com/)
1518+ @author Alexis de Lattre <alexis.delattre@akretion.com>
1519+ The licence is in the file __openerp__.py
1520+-->
1521+
1522+<openerp>
1523+<data>
1524+
1525+<menuitem id="cutoff_menu"
1526+ parent="account.menu_finance_periodical_processing"
1527+ name="Cut-offs"
1528+ sequence="24"
1529+ groups="account.group_account_user,account.group_account_manager,account.group_account_invoice"/>
1530+
1531+<!-- Form view -->
1532+<record id="account_cutoff_form" model="ir.ui.view">
1533+ <field name="name">account.cutoff.form</field>
1534+ <field name="model">account.cutoff</field>
1535+ <field name="arch" type="xml">
1536+ <form string="Cut-offs" version="7.0">
1537+ <header>
1538+ <button name="back2draft" string="Back to Draft" type="object" states="done" />
1539+ <!-- here, we have the 'get_lines' button that is supplied by the other cutoff modules -->
1540+ <button class="oe_highlight" name="create_move" string="Create Journal Entry" type="object" states="draft" attrs="{'invisible': ['|', ('line_ids', '=', False), ('state', '=', 'done')]}"/>
1541+ <field name="state" widget="statusbar" />
1542+ </header>
1543+ <sheet>
1544+ <div class="oe_title">
1545+ <h1>
1546+ <field name="type" readonly="1" />
1547+ </h1>
1548+ </div>
1549+ <group name="top">
1550+ <group name="general-params">
1551+ <field name="cutoff_date" on_change="cutoff_date_onchange(type, cutoff_date, move_label)"/>
1552+ <field name="total_cutoff_amount" widget="monetary" options="{'currency_field': 'company_currency_id'}"/>
1553+ <field name="company_id" groups="base.group_multi_company" widget="selection" />
1554+ <field name="company_currency_id" invisible="1"/>
1555+ </group>
1556+ <group name="accounting-params">
1557+ <field name="cutoff_journal_id"/>
1558+ <field name="cutoff_account_id"/>
1559+ <field name="move_label"/>
1560+ <field name="move_id"/>
1561+ </group>
1562+ </group>
1563+ <group name="lines">
1564+ <field name="line_ids" nolabel="1" context="{'type': type}"/>
1565+ </group>
1566+ </sheet>
1567+ <div class="oe_chatter">
1568+ <field name="message_follower_ids" widget="mail_followers"/>
1569+ <field name="message_ids" widget="mail_thread"/>
1570+ </div>
1571+ </form>
1572+ </field>
1573+</record>
1574+
1575+<!-- Tree view -->
1576+<record id="account_cutoff_tree" model="ir.ui.view">
1577+ <field name="name">account.cutoff.tree</field>
1578+ <field name="model">account.cutoff</field>
1579+ <field name="arch" type="xml">
1580+ <tree string="Cut-offs" colors="blue:state=='draft'">
1581+ <field name="type" invisible="context.get('type')" />
1582+ <field name="cutoff_date" />
1583+ <field name="total_cutoff_amount"/>
1584+ <field name="company_currency_id"/>
1585+ <field name="state"/>
1586+ </tree>
1587+ </field>
1588+</record>
1589+
1590+<!-- Search view -->
1591+<record id="account_cutoff_filter" model="ir.ui.view">
1592+ <field name="name">account.cutoff.filter</field>
1593+ <field name="model">account.cutoff</field>
1594+ <field name="arch" type="xml">
1595+ <search string="Search Cut-offs">
1596+ <filter name="draft" string="Draft" domain="[('state', '=', 'draft')]" />
1597+ <filter name="done" string="Done" domain="[('state', '=', 'done')]" />
1598+ </search>
1599+ </field>
1600+</record>
1601+
1602+<!-- Form view for lines -->
1603+<record id="account_cutoff_line_form" model="ir.ui.view">
1604+ <field name="name">account.cutoff.line.form</field>
1605+ <field name="model">account.cutoff.line</field>
1606+ <field name="arch" type="xml">
1607+ <form string="Cut-off Lines" version="7.0">
1608+ <group name="source" string="Source">
1609+ <field name="parent_id" invisible="not context.get('account_cutoff_line_main_view', False)"/>
1610+ <field name="partner_id"/>
1611+ <field name="name"/>
1612+ <field name="account_id"/>
1613+ <field name="cutoff_account_id"/>
1614+ <field name="analytic_account_id" groups="analytic.group_analytic_accounting"/>
1615+ <field name="tax_ids" widget="many2many_tags" invisible="'accrued' not in context.get('type', '-')"/>
1616+ <field name="amount" widget="monetary" options="{'currency_field': 'currency_id'}"/>
1617+ <field name="currency_id" invisible="1"/>
1618+ </group>
1619+ <group name="cutoff" string="Cut-off Computation">
1620+ <field name="cutoff_amount" widget="monetary" options="{'currency_field': 'company_currency_id'}"/>
1621+ <field name="company_currency_id" invisible="1"/>
1622+ </group>
1623+ <group name="tax" string="Cut-off Taxes Lines" invisible="'accrued' not in context.get('type', '-')">
1624+ <field name="tax_line_ids" nolabel="1"/>
1625+ </group>
1626+ </form>
1627+ </field>
1628+</record>
1629+
1630+<!-- Tree view for lines -->
1631+<record id="account_cutoff_line_tree" model="ir.ui.view">
1632+ <field name="name">account.cutoff.line.tree</field>
1633+ <field name="model">account.cutoff.line</field>
1634+ <field name="arch" type="xml">
1635+ <tree string="Cut-off Lines">
1636+ <field name="parent_id" invisible="not context.get('account_cutoff_line_main_view', False)"/>
1637+ <field name="partner_id"/>
1638+ <field name="name"/>
1639+ <field name="cutoff_account_code"/>
1640+ <field name="analytic_account_code" groups="analytic.group_analytic_accounting"/>
1641+ <field name="tax_ids" widget="many2many_tags" invisible="'accrued' not in context.get('type', '-')"/>
1642+ <field name="amount"/>
1643+ <field name="currency_id" groups="base.group_multi_currency"/>
1644+ <field name="cutoff_amount"/>
1645+ <field name="company_currency_id" groups="base.group_multi_currency"/>
1646+ </tree>
1647+ </field>
1648+</record>
1649+
1650+<!-- Form view for tax lines -->
1651+<record id="account_cutoff_tax_line_form" model="ir.ui.view">
1652+ <field name="name">account.cutoff.tax.line.form</field>
1653+ <field name="model">account.cutoff.tax.line</field>
1654+ <field name="arch" type="xml">
1655+ <form string="Cut-off Tax Lines" version="7.0">
1656+ <group name="tax" string="Tax">
1657+ <field name="parent_id" invisible="not context.get('account_cutoff_tax_line_main_view', False)"/>
1658+ <field name="tax_id"/>
1659+ <field name="sequence"/>
1660+ <field name="cutoff_account_id"/>
1661+ <field name="analytic_account_id" groups="analytic.group_analytic_accounting"/>
1662+ <field name="base" widget="monetary" options="{'currency_field': 'currency_id'}"/>
1663+ <field name="amount" widget="monetary" options="{'currency_field': 'currency_id'}"/>
1664+ <field name="currency_id" invisible="True"/>
1665+ </group>
1666+ <group name="cutoff" string="Cut-off Computation">
1667+ <field name="cutoff_amount" widget="monetary" options="{'currency_field': 'company_currency_id'}"/>
1668+ <field name="company_currency_id" invisible="True"/>
1669+ </group>
1670+ </form>
1671+ </field>
1672+</record>
1673+
1674+<!-- Tree view for tax lines -->
1675+<record id="account_cutoff_tax_line_tree" model="ir.ui.view">
1676+ <field name="name">account.cutoff.tax.line.tree</field>
1677+ <field name="model">account.cutoff.tax.line</field>
1678+ <field name="arch" type="xml">
1679+ <tree string="Cut-off Tax Lines">
1680+ <field name="parent_id" invisible="not context.get('account_cutoff_tax_line_main_view', False)"/>
1681+ <field name="tax_id"/>
1682+ <field name="cutoff_account_id"/>
1683+ <field name="analytic_account_id" groups="analytic.group_analytic_accounting"/>
1684+ <field name="base"/>
1685+ <field name="amount"/>
1686+ <field name="currency_id" groups="base.group_multi_currency"/>
1687+ <field name="cutoff_amount"/>
1688+ <field name="company_currency_id" groups="base.group_multi_currency"/>
1689+ <field name="sequence" invisible="True"/>
1690+ </tree>
1691+ </field>
1692+</record>
1693+
1694+<!-- Notification in the chatter -->
1695+<record id="cutoff_done" model="mail.message.subtype">
1696+ <field name="name">Cut-off Journal Entry Created</field>
1697+ <field name="res_model">account.cutoff</field>
1698+ <field name="default" eval="False"/>
1699+ <field name="description">Cut-off Journal Entry Created</field>
1700+</record>
1701+
1702+<!-- Form view for account mappings -->
1703+<record id="account_cutoff_mapping_form" model="ir.ui.view">
1704+ <field name="name">account.cutoff.mapping.form</field>
1705+ <field name="model">account.cutoff.mapping</field>
1706+ <field name="arch" type="xml">
1707+ <form string="Account Cut-off Mapping" version="7.0">
1708+ <field name="company_id" groups="base.group_multi_company" widget="selection" invisible="not context.get('account_cutoff_mapping_main_view', False)" />
1709+ <field name="account_id"/>
1710+ <field name="cutoff_account_id"/>
1711+ <field name="cutoff_type"/>
1712+ </form>
1713+ </field>
1714+</record>
1715+
1716+<!-- Tree view for account mappings -->
1717+<record id="account_cutoff_mapping_tree" model="ir.ui.view">
1718+ <field name="name">account.cutoff.mapping.tree</field>
1719+ <field name="model">account.cutoff.mapping</field>
1720+ <field name="arch" type="xml">
1721+ <tree string="Account Cut-off Mapping" editable="bottom">
1722+ <field name="company_id" groups="base.group_multi_company" widget="selection" invisible="not context.get('account_cutoff_mapping_main_view', False)" />
1723+ <field name="account_id"/>
1724+ <field name="cutoff_account_id"/>
1725+ <field name="cutoff_type"/>
1726+ </tree>
1727+ </field>
1728+</record>
1729+
1730+<!-- Action for account mappings -->
1731+<record id="account_cutoff_mapping_action" model="ir.actions.act_window">
1732+ <field name="name">Cut-off Account Mapping</field>
1733+ <field name="res_model">account.cutoff.mapping</field>
1734+ <field name="view_type">form</field>
1735+ <field name="view_mode">tree,form</field>
1736+ <field name="context">{'account_cutoff_mapping_main_view': True}</field>
1737+ <field name="help" type="html">
1738+ <p class="oe_view_nocontent_create">
1739+ Click to start a new cutoff account mapping.
1740+ </p><p>
1741+ These account mappings allow you to have an cutoff account for expense/revenue that is not the same as the original expense/revenue account, using the same concept as the fiscal positions.
1742+ </p>
1743+ </field>
1744+</record>
1745+
1746+<!-- Menu entry for account mapping -->
1747+<menuitem id="account_cutoff_mapping_menu"
1748+ parent="account.account_account_menu"
1749+ action="account_cutoff_mapping_action"
1750+ sequence="100"/>
1751+
1752+</data>
1753+</openerp>
1754
1755=== added file 'account_cutoff_base/company.py'
1756--- account_cutoff_base/company.py 1970-01-01 00:00:00 +0000
1757+++ account_cutoff_base/company.py 2013-12-24 15:32:24 +0000
1758@@ -0,0 +1,35 @@
1759+# -*- encoding: utf-8 -*-
1760+##############################################################################
1761+#
1762+# Account Cut-off Base module for OpenERP
1763+# Copyright (C) 2013 Akretion (http://www.akretion.com)
1764+# @author Alexis de Lattre <alexis.delattre@akretion.com>
1765+#
1766+# This program is free software: you can redistribute it and/or modify
1767+# it under the terms of the GNU Affero General Public License as
1768+# published by the Free Software Foundation, either version 3 of the
1769+# License, or (at your option) any later version.
1770+#
1771+# This program is distributed in the hope that it will be useful,
1772+# but WITHOUT ANY WARRANTY; without even the implied warranty of
1773+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1774+# GNU Affero General Public License for more details.
1775+#
1776+# You should have received a copy of the GNU Affero General Public License
1777+# along with this program. If not, see <http://www.gnu.org/licenses/>.
1778+#
1779+##############################################################################
1780+
1781+
1782+from openerp.osv import orm, fields
1783+
1784+
1785+class res_company(orm.Model):
1786+ _inherit = 'res.company'
1787+
1788+ _columns = {
1789+ 'default_cutoff_journal_id': fields.many2one(
1790+ 'account.journal', 'Default Cut-off Journal'),
1791+ 'cutoff_account_mapping_ids': fields.one2many(
1792+ 'account.cutoff.mapping', 'company_id', 'Cut-off Account Mapping'),
1793+ }
1794
1795=== added file 'account_cutoff_base/company_view.xml'
1796--- account_cutoff_base/company_view.xml 1970-01-01 00:00:00 +0000
1797+++ account_cutoff_base/company_view.xml 2013-12-24 15:32:24 +0000
1798@@ -0,0 +1,27 @@
1799+<?xml version="1.0" encoding="utf-8"?>
1800+
1801+<!--
1802+ Copyright (C) 2013 Akretion (http://www.akretion.com/)
1803+ @author Alexis de Lattre <alexis.delattre@akretion.com>
1804+ The licence is in the file __openerp__.py
1805+-->
1806+
1807+<openerp>
1808+<data>
1809+
1810+<record id="view_company_form" model="ir.ui.view">
1811+ <field name="name">cutoff.company.form</field>
1812+ <field name="model">res.company</field>
1813+ <field name="inherit_id" ref="base.view_company_form" />
1814+ <field name="arch" type="xml">
1815+ <group name="account_grp" position="after">
1816+ <group name="cutoff" string="Cut-offs">
1817+ <field name="default_cutoff_journal_id" />
1818+ </group>
1819+ </group>
1820+ </field>
1821+</record>
1822+
1823+
1824+</data>
1825+</openerp>
1826
1827=== added directory 'account_cutoff_base/i18n'
1828=== added file 'account_cutoff_base/i18n/account_cutoff_base.pot'
1829--- account_cutoff_base/i18n/account_cutoff_base.pot 1970-01-01 00:00:00 +0000
1830+++ account_cutoff_base/i18n/account_cutoff_base.pot 2013-12-24 15:32:24 +0000
1831@@ -0,0 +1,444 @@
1832+# Translation of OpenERP Server.
1833+# This file contains the translation of the following modules:
1834+# * account_cutoff_base
1835+#
1836+msgid ""
1837+msgstr ""
1838+"Project-Id-Version: OpenERP Server 7.0\n"
1839+"Report-Msgid-Bugs-To: \n"
1840+"POT-Creation-Date: 2013-12-24 15:25+0000\n"
1841+"PO-Revision-Date: 2013-12-24 15:25+0000\n"
1842+"Last-Translator: <>\n"
1843+"Language-Team: \n"
1844+"MIME-Version: 1.0\n"
1845+"Content-Type: text/plain; charset=UTF-8\n"
1846+"Content-Transfer-Encoding: \n"
1847+"Plural-Forms: \n"
1848+
1849+#. module: account_cutoff_base
1850+#: field:account.cutoff,line_ids:0
1851+#: view:account.cutoff.line:0
1852+msgid "Cut-off Lines"
1853+msgstr ""
1854+
1855+#. module: account_cutoff_base
1856+#: field:account.cutoff,move_id:0
1857+msgid "Cut-off Journal Entry"
1858+msgstr ""
1859+
1860+#. module: account_cutoff_base
1861+#: help:account.cutoff,move_label:0
1862+msgid "This label will be written in the 'Name' field of the Cut-off Account Move Lines and in the 'Reference' field of the Cut-off Account Move."
1863+msgstr ""
1864+
1865+#. module: account_cutoff_base
1866+#: view:account.cutoff:0
1867+msgid "Search Cut-offs"
1868+msgstr ""
1869+
1870+#. module: account_cutoff_base
1871+#: help:account.cutoff,state:0
1872+msgid "State of the cutoff. When the Journal Entry is created, the state is set to 'Done' and the fields become read-only."
1873+msgstr ""
1874+
1875+#. module: account_cutoff_base
1876+#: model:mail.message.subtype,description:account_cutoff_base.cutoff_done
1877+#: model:mail.message.subtype,name:account_cutoff_base.cutoff_done
1878+msgid "Cut-off Journal Entry Created"
1879+msgstr ""
1880+
1881+#. module: account_cutoff_base
1882+#: field:account.cutoff.mapping,cutoff_type:0
1883+msgid "Cut-off Type"
1884+msgstr ""
1885+
1886+#. module: account_cutoff_base
1887+#: code:addons/account_cutoff_base/account_cutoff.py:241
1888+#, python-format
1889+msgid "The Cut-off Journal Entry already exists. You should delete it before running this function."
1890+msgstr ""
1891+
1892+#. module: account_cutoff_base
1893+#: view:account.cutoff.line:0
1894+msgid "Source"
1895+msgstr ""
1896+
1897+#. module: account_cutoff_base
1898+#: field:account.cutoff,message_follower_ids:0
1899+msgid "Followers"
1900+msgstr ""
1901+
1902+#. module: account_cutoff_base
1903+#: field:account.cutoff.line,cutoff_account_code:0
1904+msgid "Cut-off Account Code"
1905+msgstr ""
1906+
1907+#. module: account_cutoff_base
1908+#: selection:account.cutoff,type:0
1909+#: selection:account.cutoff.mapping,cutoff_type:0
1910+msgid "Prepaid Expense"
1911+msgstr ""
1912+
1913+#. module: account_cutoff_base
1914+#: code:addons/account_cutoff_base/account_cutoff.py:246
1915+#, python-format
1916+msgid "There are no lines on this Cut-off, so we can't create a Journal Entry."
1917+msgstr ""
1918+
1919+#. module: account_cutoff_base
1920+#: view:account.cutoff.mapping:0
1921+#: model:ir.model,name:account_cutoff_base.model_account_cutoff_mapping
1922+msgid "Account Cut-off Mapping"
1923+msgstr ""
1924+
1925+#. module: account_cutoff_base
1926+#: help:account.cutoff.tax.line,amount:0
1927+msgid "Tax Amount in the currency of the PO."
1928+msgstr ""
1929+
1930+#. module: account_cutoff_base
1931+#: help:account.cutoff.tax.line,cutoff_amount:0
1932+msgid "Tax Cut-off Amount in the company currency."
1933+msgstr ""
1934+
1935+#. module: account_cutoff_base
1936+#: selection:account.cutoff,type:0
1937+#: selection:account.cutoff.mapping,cutoff_type:0
1938+msgid "Accrued Revenue"
1939+msgstr ""
1940+
1941+#. module: account_cutoff_base
1942+#: field:account.cutoff.line,partner_id:0
1943+msgid "Partner"
1944+msgstr ""
1945+
1946+#. module: account_cutoff_base
1947+#: field:account.cutoff,cutoff_date:0
1948+msgid "Cut-off Date"
1949+msgstr ""
1950+
1951+#. module: account_cutoff_base
1952+#: field:account.cutoff.line,name:0
1953+msgid "Description"
1954+msgstr ""
1955+
1956+#. module: account_cutoff_base
1957+#: field:account.cutoff,message_unread:0
1958+msgid "Unread Messages"
1959+msgstr ""
1960+
1961+#. module: account_cutoff_base
1962+#: field:account.cutoff,type:0
1963+msgid "Type"
1964+msgstr ""
1965+
1966+#. module: account_cutoff_base
1967+#: field:account.cutoff,company_id:0
1968+#: field:account.cutoff.mapping,company_id:0
1969+msgid "Company"
1970+msgstr ""
1971+
1972+#. module: account_cutoff_base
1973+#: field:account.cutoff,cutoff_journal_id:0
1974+msgid "Cut-off Account Journal"
1975+msgstr ""
1976+
1977+#. module: account_cutoff_base
1978+#: model:ir.model,name:account_cutoff_base.model_account_cutoff_tax_line
1979+msgid "Account Cut-off Tax Line"
1980+msgstr ""
1981+
1982+#. module: account_cutoff_base
1983+#: model:ir.actions.act_window,help:account_cutoff_base.account_cutoff_mapping_action
1984+msgid "<p class=\"oe_view_nocontent_create\">\n"
1985+" Click to start a new cutoff account mapping.\n"
1986+" </p><p>\n"
1987+" These account mappings allow you to have an cutoff account for expense/revenue that is not the same as the original expense/revenue account, using the same concept as the fiscal positions.\n"
1988+" </p>\n"
1989+" "
1990+msgstr ""
1991+
1992+#. module: account_cutoff_base
1993+#: help:account.cutoff.line,currency_id:0
1994+msgid "Currency of the 'Amount' field."
1995+msgstr ""
1996+
1997+#. module: account_cutoff_base
1998+#: help:account.cutoff,message_unread:0
1999+msgid "If checked new messages require your attention."
2000+msgstr ""
2001+
2002+#. module: account_cutoff_base
2003+#: selection:account.cutoff,type:0
2004+#: selection:account.cutoff.mapping,cutoff_type:0
2005+msgid "Accrued Expense"
2006+msgstr ""
2007+
2008+#. module: account_cutoff_base
2009+#: field:account.cutoff,total_cutoff_amount:0
2010+msgid "Total Cut-off Amount"
2011+msgstr ""
2012+
2013+#. module: account_cutoff_base
2014+#: field:account.cutoff,company_currency_id:0
2015+#: field:account.cutoff.line,company_currency_id:0
2016+#: field:account.cutoff.tax.line,company_currency_id:0
2017+msgid "Company Currency"
2018+msgstr ""
2019+
2020+#. module: account_cutoff_base
2021+#: field:account.cutoff.tax.line,base:0
2022+msgid "Base"
2023+msgstr ""
2024+
2025+#. module: account_cutoff_base
2026+#: field:account.cutoff,message_is_follower:0
2027+msgid "Is a Follower"
2028+msgstr ""
2029+
2030+#. module: account_cutoff_base
2031+#: field:res.company,default_cutoff_journal_id:0
2032+msgid "Default Cut-off Journal"
2033+msgstr ""
2034+
2035+#. module: account_cutoff_base
2036+#: view:account.cutoff:0
2037+#: selection:account.cutoff,state:0
2038+msgid "Done"
2039+msgstr ""
2040+
2041+#. module: account_cutoff_base
2042+#: field:account.cutoff.line,parent_id:0
2043+msgid "Cut-off"
2044+msgstr ""
2045+
2046+#. module: account_cutoff_base
2047+#: view:account.cutoff:0
2048+msgid "Back to Draft"
2049+msgstr ""
2050+
2051+#. module: account_cutoff_base
2052+#: code:addons/account_cutoff_base/account_cutoff.py:240
2053+#: code:addons/account_cutoff_base/account_cutoff.py:245
2054+#, python-format
2055+msgid "Error:"
2056+msgstr ""
2057+
2058+#. module: account_cutoff_base
2059+#: sql_constraint:account.cutoff:0
2060+msgid "A cutoff of the same type already exists with this cut-off date !"
2061+msgstr ""
2062+
2063+#. module: account_cutoff_base
2064+#: field:account.cutoff.tax.line,parent_id:0
2065+#: model:ir.model,name:account_cutoff_base.model_account_cutoff_line
2066+msgid "Account Cut-off Line"
2067+msgstr ""
2068+
2069+#. module: account_cutoff_base
2070+#: field:account.cutoff.line,account_id:0
2071+msgid "Account"
2072+msgstr ""
2073+
2074+#. module: account_cutoff_base
2075+#: field:account.cutoff.line,tax_line_ids:0
2076+#: view:account.cutoff.tax.line:0
2077+msgid "Cut-off Tax Lines"
2078+msgstr ""
2079+
2080+#. module: account_cutoff_base
2081+#: field:account.cutoff.tax.line,cutoff_amount:0
2082+msgid "Cut-off Tax Amount"
2083+msgstr ""
2084+
2085+#. module: account_cutoff_base
2086+#: field:account.cutoff,message_ids:0
2087+msgid "Messages"
2088+msgstr ""
2089+
2090+#. module: account_cutoff_base
2091+#: model:ir.model,name:account_cutoff_base.model_account_cutoff
2092+msgid "Account Cut-off"
2093+msgstr ""
2094+
2095+#. module: account_cutoff_base
2096+#: field:account.cutoff.tax.line,amount:0
2097+msgid "Tax Amount"
2098+msgstr ""
2099+
2100+#. module: account_cutoff_base
2101+#: model:ir.model,name:account_cutoff_base.model_res_company
2102+msgid "Companies"
2103+msgstr ""
2104+
2105+#. module: account_cutoff_base
2106+#: field:account.cutoff.line,tax_ids:0
2107+msgid "Taxes"
2108+msgstr ""
2109+
2110+#. module: account_cutoff_base
2111+#: view:account.cutoff:0
2112+#: model:ir.ui.menu,name:account_cutoff_base.cutoff_menu
2113+#: view:res.company:0
2114+msgid "Cut-offs"
2115+msgstr ""
2116+
2117+#. module: account_cutoff_base
2118+#: view:account.cutoff:0
2119+msgid "Create Journal Entry"
2120+msgstr ""
2121+
2122+#. module: account_cutoff_base
2123+#: field:account.cutoff.line,amount:0
2124+msgid "Amount"
2125+msgstr ""
2126+
2127+#. module: account_cutoff_base
2128+#: help:account.cutoff,message_ids:0
2129+msgid "Messages and communication history"
2130+msgstr ""
2131+
2132+#. module: account_cutoff_base
2133+#: field:account.cutoff.mapping,account_id:0
2134+msgid "Regular Account"
2135+msgstr ""
2136+
2137+#. module: account_cutoff_base
2138+#: field:account.cutoff,move_label:0
2139+msgid "Label of the Cut-off Journal Entry"
2140+msgstr ""
2141+
2142+#. module: account_cutoff_base
2143+#: field:account.cutoff,message_summary:0
2144+msgid "Summary"
2145+msgstr ""
2146+
2147+#. module: account_cutoff_base
2148+#: view:account.cutoff.line:0
2149+msgid "Cut-off Taxes Lines"
2150+msgstr ""
2151+
2152+#. module: account_cutoff_base
2153+#: selection:account.cutoff,type:0
2154+#: selection:account.cutoff.mapping,cutoff_type:0
2155+msgid "Prepaid Revenue"
2156+msgstr ""
2157+
2158+#. module: account_cutoff_base
2159+#: code:addons/account_cutoff_base/account_cutoff.py:133
2160+#, python-format
2161+msgid "Prepaid Expense%s"
2162+msgstr ""
2163+
2164+#. module: account_cutoff_base
2165+#: view:account.cutoff.line:0
2166+#: view:account.cutoff.tax.line:0
2167+msgid "Cut-off Computation"
2168+msgstr ""
2169+
2170+#. module: account_cutoff_base
2171+#: selection:account.cutoff.mapping,cutoff_type:0
2172+msgid "All Cut-off Types"
2173+msgstr ""
2174+
2175+#. module: account_cutoff_base
2176+#: help:account.cutoff,message_summary:0
2177+msgid "Holds the Chatter summary (number of messages, ...). This summary is directly in html format in order to be inserted in kanban views."
2178+msgstr ""
2179+
2180+#. module: account_cutoff_base
2181+#: field:account.cutoff,state:0
2182+msgid "State"
2183+msgstr ""
2184+
2185+#. module: account_cutoff_base
2186+#: help:account.cutoff.tax.line,base:0
2187+msgid "Base Amount in the currency of the PO."
2188+msgstr ""
2189+
2190+#. module: account_cutoff_base
2191+#: code:addons/account_cutoff_base/account_cutoff.py:129
2192+#, python-format
2193+msgid "Accrued Revenue%s"
2194+msgstr ""
2195+
2196+#. module: account_cutoff_base
2197+#: field:account.cutoff.tax.line,sequence:0
2198+msgid "Sequence"
2199+msgstr ""
2200+
2201+#. module: account_cutoff_base
2202+#: view:account.cutoff.tax.line:0
2203+#: field:account.cutoff.tax.line,tax_id:0
2204+msgid "Tax"
2205+msgstr ""
2206+
2207+#. module: account_cutoff_base
2208+#: field:account.cutoff.line,currency_id:0
2209+msgid "Amount Currency"
2210+msgstr ""
2211+
2212+#. module: account_cutoff_base
2213+#: field:account.cutoff,cutoff_account_id:0
2214+#: field:account.cutoff.line,cutoff_account_id:0
2215+#: field:account.cutoff.mapping,cutoff_account_id:0
2216+#: field:account.cutoff.tax.line,cutoff_account_id:0
2217+msgid "Cut-off Account"
2218+msgstr ""
2219+
2220+#. module: account_cutoff_base
2221+#: field:account.cutoff.line,analytic_account_id:0
2222+#: field:account.cutoff.tax.line,analytic_account_id:0
2223+msgid "Analytic Account"
2224+msgstr ""
2225+
2226+#. module: account_cutoff_base
2227+#: field:account.cutoff.tax.line,currency_id:0
2228+msgid "Currency"
2229+msgstr ""
2230+
2231+#. module: account_cutoff_base
2232+#: field:account.cutoff.line,analytic_account_code:0
2233+msgid "Analytic Account Code"
2234+msgstr ""
2235+
2236+#. module: account_cutoff_base
2237+#: model:ir.actions.act_window,name:account_cutoff_base.account_cutoff_mapping_action
2238+#: model:ir.ui.menu,name:account_cutoff_base.account_cutoff_mapping_menu
2239+#: field:res.company,cutoff_account_mapping_ids:0
2240+msgid "Cut-off Account Mapping"
2241+msgstr ""
2242+
2243+#. module: account_cutoff_base
2244+#: code:addons/account_cutoff_base/account_cutoff.py:131
2245+#, python-format
2246+msgid "Prepaid Revenue%s"
2247+msgstr ""
2248+
2249+#. module: account_cutoff_base
2250+#: help:account.cutoff.line,amount:0
2251+msgid "Amount that is used as base to compute the Cut-off Amount. This Amount is in the 'Amount Currency', which may be different from the 'Company Currency'."
2252+msgstr ""
2253+
2254+#. module: account_cutoff_base
2255+#: view:account.cutoff:0
2256+#: selection:account.cutoff,state:0
2257+msgid "Draft"
2258+msgstr ""
2259+
2260+#. module: account_cutoff_base
2261+#: help:account.cutoff.line,cutoff_amount:0
2262+msgid "Cut-off Amount without taxes in the Company Currency."
2263+msgstr ""
2264+
2265+#. module: account_cutoff_base
2266+#: code:addons/account_cutoff_base/account_cutoff.py:127
2267+#, python-format
2268+msgid "Accrued Expense%s"
2269+msgstr ""
2270+
2271+#. module: account_cutoff_base
2272+#: field:account.cutoff.line,cutoff_amount:0
2273+msgid "Cut-off Amount"
2274+msgstr ""
2275+
2276
2277=== added directory 'account_cutoff_base/security'
2278=== added file 'account_cutoff_base/security/ir.model.access.csv'
2279--- account_cutoff_base/security/ir.model.access.csv 1970-01-01 00:00:00 +0000
2280+++ account_cutoff_base/security/ir.model.access.csv 2013-12-24 15:32:24 +0000
2281@@ -0,0 +1,9 @@
2282+id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
2283+access_account_cutoff_mapping,Full access on account.cutoff.mapping,model_account_cutoff_mapping,account.group_account_manager,1,1,1,1
2284+access_account_cutoff_mapping_user,Read access on account.cutoff.mapping,model_account_cutoff_mapping,base.group_user,1,0,0,0
2285+access_account_cutoff,Full access on account.cutoff,model_account_cutoff,account.group_account_manager,1,1,1,1
2286+access_account_cutoff_read,Read access on account.cutoff,model_account_cutoff,account.group_account_user,1,0,0,0
2287+access_account_cutoff_line,Full access on account.cutoff.line,model_account_cutoff_line,account.group_account_manager,1,1,1,1
2288+access_account_cutoff_line_read,Read access on account.cutoff.line,model_account_cutoff_line,account.group_account_user,1,0,0,0
2289+access_account_cutoff_tax_line,Full access on account.cutoff.tax.line,model_account_cutoff_tax_line,account.group_account_manager,1,1,1,1
2290+access_account_cutoff_tax_line_read,Read access on account.cutoff.tax.line,model_account_cutoff_tax_line,account.group_account_user,1,0,0,0
2291
2292=== added directory 'account_cutoff_prepaid'
2293=== added file 'account_cutoff_prepaid/__init__.py'
2294--- account_cutoff_prepaid/__init__.py 1970-01-01 00:00:00 +0000
2295+++ account_cutoff_prepaid/__init__.py 2013-12-24 15:32:24 +0000
2296@@ -0,0 +1,26 @@
2297+# -*- encoding: utf-8 -*-
2298+##############################################################################
2299+#
2300+# Account Cut-off Prepaid module for OpenERP
2301+# Copyright (C) 2013 Akretion (http://www.akretion.com)
2302+# @author Alexis de Lattre <alexis.delattre@akretion.com>
2303+#
2304+# This program is free software: you can redistribute it and/or modify
2305+# it under the terms of the GNU Affero General Public License as
2306+# published by the Free Software Foundation, either version 3 of the
2307+# License, or (at your option) any later version.
2308+#
2309+# This program is distributed in the hope that it will be useful,
2310+# but WITHOUT ANY WARRANTY; without even the implied warranty of
2311+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2312+# GNU Affero General Public License for more details.
2313+#
2314+# You should have received a copy of the GNU Affero General Public License
2315+# along with this program. If not, see <http://www.gnu.org/licenses/>.
2316+#
2317+##############################################################################
2318+
2319+from . import company
2320+from . import product
2321+from . import account
2322+from . import account_cutoff
2323
2324=== added file 'account_cutoff_prepaid/__openerp__.py'
2325--- account_cutoff_prepaid/__openerp__.py 1970-01-01 00:00:00 +0000
2326+++ account_cutoff_prepaid/__openerp__.py 2013-12-24 15:32:24 +0000
2327@@ -0,0 +1,57 @@
2328+# -*- encoding: utf-8 -*-
2329+##############################################################################
2330+#
2331+# Account Cut-off Prepaid module for OpenERP
2332+# Copyright (C) 2013 Akretion (http://www.akretion.com)
2333+# @author Alexis de Lattre <alexis.delattre@akretion.com>
2334+#
2335+# This program is free software: you can redistribute it and/or modify
2336+# it under the terms of the GNU Affero General Public License as
2337+# published by the Free Software Foundation, either version 3 of the
2338+# License, or (at your option) any later version.
2339+#
2340+# This program is distributed in the hope that it will be useful,
2341+# but WITHOUT ANY WARRANTY; without even the implied warranty of
2342+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2343+# GNU Affero General Public License for more details.
2344+#
2345+# You should have received a copy of the GNU Affero General Public License
2346+# along with this program. If not, see <http://www.gnu.org/licenses/>.
2347+#
2348+##############################################################################
2349+
2350+
2351+{
2352+ 'name': 'Account Cut-off Prepaid',
2353+ 'version': '0.1',
2354+ 'category': 'Accounting & Finance',
2355+ 'license': 'AGPL-3',
2356+ 'summary': 'Prepaid Expense, Prepaid Revenue',
2357+ 'description': """
2358+Manage prepaid expense and revenue based on start and end dates
2359+===============================================================
2360+
2361+This module adds a **Start Date** and **End Date** field on invoice lines. For example, if you have an insurance contrat for your company that run from April 1st 2013 to March 31st 2014, you will enter these dates as start and end dates on the supplier invoice line. If your fiscal year ends on December 31st 2013, 3 months of expenses are part of the 2014 fiscal year and should not be part of the 2013 fiscal year. So, thanks to this module, you will create a *Prepaid Expense* on December 31st 2013 and OpenERP will identify this expense with the 3 months that are after the cut-off date and propose to generate the appropriate cut-off journal entry.
2362+
2363+Please contact Alexis de Lattre from Akretion <alexis.delattre@akretion.com> for any help or question about this module.
2364+ """,
2365+ 'author': 'Akretion',
2366+ 'website': 'http://www.akretion.com',
2367+ 'depends': ['account_cutoff_base'],
2368+ 'data': [
2369+ 'company_view.xml',
2370+ 'product_view.xml',
2371+ 'account_invoice_view.xml',
2372+ 'account_view.xml',
2373+ 'account_cutoff_view.xml',
2374+ ],
2375+ 'demo': ['product_demo.xml'],
2376+ 'images': [
2377+ 'images/prepaid_revenue_draft.jpg',
2378+ 'images/prepaid_revenue_journal_entry.jpg',
2379+ 'images/prepaid_revenue_done.jpg',
2380+ ],
2381+ 'installable': True,
2382+ 'active': False,
2383+ 'application': True,
2384+}
2385
2386=== added file 'account_cutoff_prepaid/account.py'
2387--- account_cutoff_prepaid/account.py 1970-01-01 00:00:00 +0000
2388+++ account_cutoff_prepaid/account.py 2013-12-24 15:32:24 +0000
2389@@ -0,0 +1,150 @@
2390+# -*- encoding: utf-8 -*-
2391+##############################################################################
2392+#
2393+# Account Cut-off Prepaid module for OpenERP
2394+# Copyright (C) 2013 Akretion (http://www.akretion.com)
2395+# @author Alexis de Lattre <alexis.delattre@akretion.com>
2396+#
2397+# This program is free software: you can redistribute it and/or modify
2398+# it under the terms of the GNU Affero General Public License as
2399+# published by the Free Software Foundation, either version 3 of the
2400+# License, or (at your option) any later version.
2401+#
2402+# This program is distributed in the hope that it will be useful,
2403+# but WITHOUT ANY WARRANTY; without even the implied warranty of
2404+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2405+# GNU Affero General Public License for more details.
2406+#
2407+# You should have received a copy of the GNU Affero General Public License
2408+# along with this program. If not, see <http://www.gnu.org/licenses/>.
2409+#
2410+##############################################################################
2411+
2412+
2413+from openerp.osv import orm, fields
2414+from openerp.tools.translate import _
2415+
2416+
2417+class account_invoice_line(orm.Model):
2418+ _inherit = 'account.invoice.line'
2419+
2420+ _columns = {
2421+ 'start_date': fields.date('Start Date'),
2422+ 'end_date': fields.date('End Date'),
2423+ }
2424+
2425+ def _check_start_end_dates(self, cr, uid, ids):
2426+ for invline in self.browse(cr, uid, ids):
2427+ if invline.start_date and not invline.end_date:
2428+ raise orm.except_orm(
2429+ _('Error:'),
2430+ _("Missing End Date for invoice line with "
2431+ "Description '%s'.")
2432+ % (invline.name))
2433+ if invline.end_date and not invline.start_date:
2434+ raise orm.except_orm(
2435+ _('Error:'),
2436+ _("Missing Start Date for invoice line with "
2437+ "Description '%s'.")
2438+ % (invline.name))
2439+ if invline.end_date and invline.start_date and \
2440+ invline.start_date > invline.end_date:
2441+ raise orm.except_orm(
2442+ _('Error:'),
2443+ _("Start Date should be before or be the same as "
2444+ "End Date for invoice line with Description '%s'.")
2445+ % (invline.name))
2446+ # Note : we can't check invline.product_id.must_have_dates
2447+ # have start_date and end_date here, because it would
2448+ # block automatic invoice generation. So we do the check
2449+ # upon validation of the invoice (see below the function
2450+ # action_move_create)
2451+ return True
2452+
2453+ _constraints = [
2454+ (_check_start_end_dates, "Error msg in raise",
2455+ ['start_date', 'end_date', 'product_id']),
2456+ ]
2457+
2458+ def move_line_get_item(self, cr, uid, line, context=None):
2459+ res = super(account_invoice_line, self).move_line_get_item(
2460+ cr, uid, line, context=context)
2461+ res['start_date'] = line.start_date
2462+ res['end_date'] = line.end_date
2463+ return res
2464+
2465+
2466+class account_move_line(orm.Model):
2467+ _inherit = "account.move.line"
2468+
2469+ _columns = {
2470+ 'start_date': fields.date('Start Date'),
2471+ 'end_date': fields.date('End Date'),
2472+ }
2473+
2474+ def _check_start_end_dates(self, cr, uid, ids):
2475+ for moveline in self.browse(cr, uid, ids):
2476+ if moveline.start_date and not moveline.end_date:
2477+ raise orm.except_orm(
2478+ _('Error:'),
2479+ _("Missing End Date for move line with Name '%s'.")
2480+ % (moveline.name))
2481+ if moveline.end_date and not moveline.start_date:
2482+ raise orm.except_orm(
2483+ _('Error:'),
2484+ _("Missing Start Date for move line with Name '%s'.")
2485+ % (moveline.name))
2486+ if moveline.end_date and moveline.start_date and \
2487+ moveline.start_date > moveline.end_date:
2488+ raise orm.except_orm(
2489+ _('Error:'),
2490+ _("Start Date should be before End Date for move line "
2491+ "with Name '%s'.")
2492+ % (moveline.name))
2493+ # should we check that it's related to an expense / revenue ?
2494+ # -> I don't think so
2495+ return True
2496+
2497+ _constraints = [(
2498+ _check_start_end_dates,
2499+ "Error msg in raise",
2500+ ['start_date', 'end_date']
2501+ )]
2502+
2503+
2504+class account_invoice(orm.Model):
2505+ _inherit = 'account.invoice'
2506+
2507+ def inv_line_characteristic_hashcode(self, invoice, invoice_line):
2508+ '''Add start and end dates to hashcode used when the option "Group
2509+ Invoice Lines" is active on the Account Journal'''
2510+ code = super(account_invoice, self).inv_line_characteristic_hashcode(
2511+ invoice, invoice_line)
2512+ hashcode = '%s-%s-%s' % (
2513+ code, invoice_line.get('start_date', 'False'),
2514+ invoice_line.get('end_date', 'False'),
2515+ )
2516+ return hashcode
2517+
2518+ def line_get_convert(self, cr, uid, x, part, date, context=None):
2519+ res = super(account_invoice, self).line_get_convert(
2520+ cr, uid, x, part, date, context=context)
2521+ res['start_date'] = x.get('start_date', False)
2522+ res['end_date'] = x.get('end_date', False)
2523+ return res
2524+
2525+ def action_move_create(self, cr, uid, ids, context=None):
2526+ '''Check that products with must_have_dates=True have
2527+ Start and End Dates'''
2528+ for invoice in self.browse(cr, uid, ids, context=context):
2529+ for invline in invoice.invoice_line:
2530+ if invline.product_id and invline.product_id.must_have_dates:
2531+ if not invline.start_date or not invline.end_date:
2532+ raise orm.except_orm(
2533+ _('Error:'),
2534+ _("Missing Start Date and End Date for invoice "
2535+ "line with Product '%s' which has the "
2536+ "property 'Must Have Start and End Dates'.")
2537+ % (invline.product_id.name))
2538+ return super(account_invoice, self).action_move_create(
2539+ cr, uid, ids, context=context)
2540
2541=== added file 'account_cutoff_prepaid/account_cutoff.py'
2542--- account_cutoff_prepaid/account_cutoff.py 1970-01-01 00:00:00 +0000
2543+++ account_cutoff_prepaid/account_cutoff.py 2013-12-24 15:32:24 +0000
2544@@ -0,0 +1,193 @@
2545+# -*- encoding: utf-8 -*-
2546+##############################################################################
2547+#
2548+# Account Cut-off Prepaid module for OpenERP
2549+# Copyright (C) 2013 Akretion (http://www.akretion.com)
2550+# @author Alexis de Lattre <alexis.delattre@akretion.com>
2551+#
2552+# This program is free software: you can redistribute it and/or modify
2553+# it under the terms of the GNU Affero General Public License as
2554+# published by the Free Software Foundation, either version 3 of the
2555+# License, or (at your option) any later version.
2556+#
2557+# This program is distributed in the hope that it will be useful,
2558+# but WITHOUT ANY WARRANTY; without even the implied warranty of
2559+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2560+# GNU Affero General Public License for more details.
2561+#
2562+# You should have received a copy of the GNU Affero General Public License
2563+# along with this program. If not, see <http://www.gnu.org/licenses/>.
2564+#
2565+##############################################################################
2566+
2567+
2568+from openerp.osv import orm, fields
2569+from openerp.tools.translate import _
2570+from datetime import datetime
2571+
2572+
2573+class account_cutoff(orm.Model):
2574+ _inherit = 'account.cutoff'
2575+
2576+ _columns = {
2577+ 'source_journal_ids': fields.many2many(
2578+ 'account.journal', id1='cutoff_id', id2='journal_id',
2579+ string='Source Journals', readonly=True,
2580+ states={'draft': [('readonly', False)]}),
2581+ }
2582+
2583+ def _get_default_source_journals(self, cr, uid, context=None):
2584+ if context is None:
2585+ context = {}
2586+ journal_obj = self.pool['account.journal']
2587+ res = []
2588+ type = context.get('type')
2589+ mapping = {
2590+ 'prepaid_expense': ('purchase', 'purchase_refund'),
2591+ 'prepaid_revenue': ('sale', 'sale_refund'),
2592+ }
2593+ if type in mapping:
2594+ src_journal_ids = journal_obj.search(
2595+ cr, uid, [('type', 'in', mapping[type])])
2596+ if src_journal_ids:
2597+ res = src_journal_ids
2598+ return res
2599+
2600+ _defaults = {
2601+ 'source_journal_ids': _get_default_source_journals,
2602+ }
2603+
2604+ _sql_constraints = [(
2605+ 'date_type_company_uniq',
2606+ 'unique(cutoff_date, company_id, type)',
2607+ 'A cut-off of the same type already exists with this cut-off date !'
2608+ )]
2609+
2610+ def _prepare_prepaid_lines(
2611+ self, cr, uid, ids, aml, cur_cutoff, mapping, context=None):
2612+ start_date = datetime.strptime(aml['start_date'], '%Y-%m-%d')
2613+ end_date = datetime.strptime(aml['end_date'], '%Y-%m-%d')
2614+ cutoff_date_str = cur_cutoff['cutoff_date']
2615+ cutoff_date = datetime.strptime(cutoff_date_str, '%Y-%m-%d')
2616+ # Here, we compute the amount of the cutoff
2617+ # That's the important part !
2618+ total_days = (end_date - start_date).days + 1
2619+ if aml['start_date'] > cutoff_date_str:
2620+ after_cutoff_days = total_days
2621+ cutoff_amount = -1 * (aml['credit'] - aml['debit'])
2622+ else:
2623+ after_cutoff_days = (end_date - cutoff_date).days
2624+ if total_days:
2625+ cutoff_amount = -1 * (aml['credit'] - aml['debit'])\
2626+ * after_cutoff_days / total_days
2627+ else:
2628+ raise orm.except_orm(
2629+ _('Error:'),
2630+ "Should never happen. Total days should always be > 0")
2631+
2632+ # we use account mapping here
2633+ if aml['account_id'][0] in mapping:
2634+ cutoff_account_id = mapping[aml['account_id'][0]]
2635+ else:
2636+ cutoff_account_id = aml['account_id'][0]
2637+
2638+ res = {
2639+ 'parent_id': ids[0],
2640+ 'move_line_id': aml['id'],
2641+ 'partner_id': aml['partner_id'] and aml['partner_id'][0] or False,
2642+ 'name': aml['name'],
2643+ 'start_date': aml['start_date'],
2644+ 'end_date': aml['end_date'],
2645+ 'account_id': aml['account_id'][0],
2646+ 'cutoff_account_id': cutoff_account_id,
2647+ 'analytic_account_id':
2648+ aml['analytic_account_id'] and aml['analytic_account_id'][0]
2649+ or False,
2650+ 'total_days': total_days,
2651+ 'after_cutoff_days': after_cutoff_days,
2652+ 'amount': aml['credit'] - aml['debit'],
2653+ 'currency_id': cur_cutoff['company_currency_id'][0],
2654+ 'cutoff_amount': cutoff_amount,
2655+ }
2656+ return res
2657+
2658+ def get_prepaid_lines(self, cr, uid, ids, context=None):
2659+ assert len(ids) == 1,\
2660+ 'This function should only be used for a single id at a time'
2661+ aml_obj = self.pool['account.move.line']
2662+ line_obj = self.pool['account.cutoff.line']
2663+ mapping_obj = self.pool['account.cutoff.mapping']
2664+ cur_cutoff = self.read(
2665+ cr, uid, ids[0], [
2666+ 'line_ids', 'source_journal_ids', 'cutoff_date', 'company_id',
2667+ 'type', 'company_currency_id'
2668+ ],
2669+ context=context)
2670+ src_journal_ids = cur_cutoff['source_journal_ids']
2671+ if not src_journal_ids:
2672+ raise orm.except_orm(
2673+ _('Error:'), _("You should set at least one Source Journal."))
2674+ cutoff_date_str = cur_cutoff['cutoff_date']
2675+ # Delete existing lines
2676+ if cur_cutoff['line_ids']:
2677+ line_obj.unlink(cr, uid, cur_cutoff['line_ids'], context=context)
2678+
2679+ # Search for account move lines in the source journals
2680+ aml_ids = aml_obj.search(cr, uid, [
2681+ ('start_date', '!=', False),
2682+ ('journal_id', 'in', src_journal_ids),
2683+ ('end_date', '>', cutoff_date_str),
2684+ ('date', '<=', cutoff_date_str)
2685+ ], context=context)
2686+ # Create mapping dict
2687+ mapping = mapping_obj._get_mapping_dict(
2688+ cr, uid, cur_cutoff['company_id'][0], cur_cutoff['type'],
2689+ context=context)
2690+
2691+ # Loop on selected account move lines to create the cutoff lines
2692+ for aml in aml_obj.read(
2693+ cr, uid, aml_ids, [
2694+ 'credit', 'debit', 'start_date', 'end_date', 'account_id',
2695+ 'analytic_account_id', 'partner_id', 'name'
2696+ ],
2697+ context=context):
2698+
2699+ line_obj.create(
2700+ cr, uid, self._prepare_prepaid_lines(
2701+ cr, uid, ids, aml, cur_cutoff, mapping, context=context),
2702+ context=context)
2703+ return True
2704+
2705+ def _inherit_default_cutoff_account_id(self, cr, uid, context=None):
2706+ if context is None:
2707+ context = {}
2708+ account_id = super(account_cutoff, self).\
2709+ _inherit_default_cutoff_account_id(cr, uid, context=context)
2710+ type = context.get('type')
2711+ company = self.pool['res.users'].browse(
2712+ cr, uid, uid, context=context).company_id
2713+ if type == 'prepaid_revenue':
2714+ account_id = company.default_prepaid_revenue_account_id.id or False
2715+ elif type == 'prepaid_expense':
2716+ account_id = company.default_prepaid_expense_account_id.id or False
2717+ return account_id
2718+
2719+
2720+class account_cutoff_line(orm.Model):
2721+ _inherit = 'account.cutoff.line'
2722+
2723+ _columns = {
2724+ 'move_line_id': fields.many2one(
2725+ 'account.move.line', 'Accout Move Line', readonly=True),
2726+ 'move_date': fields.related(
2727+ 'move_line_id', 'date', type='date',
2728+ string='Account Move Date', readonly=True),
2729+ 'invoice_id': fields.related(
2730+ 'move_line_id', 'invoice', type='many2one',
2731+ relation='account.invoice', string='Invoice', readonly=True),
2732+ 'start_date': fields.date('Start Date', readonly=True),
2733+ 'end_date': fields.date('End Date', readonly=True),
2734+ 'total_days': fields.integer('Total Number of Days', readonly=True),
2735+ 'after_cutoff_days': fields.integer(
2736+ 'Number of Days after Cut-off Date', readonly=True),
2737+ }
2738
2739=== added file 'account_cutoff_prepaid/account_cutoff_view.xml'
2740--- account_cutoff_prepaid/account_cutoff_view.xml 1970-01-01 00:00:00 +0000
2741+++ account_cutoff_prepaid/account_cutoff_view.xml 2013-12-24 15:32:24 +0000
2742@@ -0,0 +1,115 @@
2743+<?xml version="1.0" encoding="utf-8"?>
2744+
2745+<!--
2746+ Copyright (C) 2013 Akretion (http://www.akretion.com/)
2747+ @author Alexis de Lattre <alexis.delattre@akretion.com>
2748+ The licence is in the file __openerp__.py
2749+-->
2750+
2751+<openerp>
2752+<data>
2753+
2754+<!-- Form view -->
2755+<record id="account_cutoff_form" model="ir.ui.view">
2756+ <field name="name">account.cutoff.prepaid.form</field>
2757+ <field name="model">account.cutoff</field>
2758+ <field name="inherit_id" ref="account_cutoff_base.account_cutoff_form"/>
2759+ <field name="arch" type="xml">
2760+ <button name="back2draft" position="after">
2761+ <button class="oe_highlight" name="get_prepaid_lines" string="Re-Generate Lines" type="object" states="draft" invisible="'prepaid' not in context.get('type', '-')"/>
2762+ </button>
2763+ <field name="cutoff_date" position="after">
2764+ <field name="source_journal_ids" widget="many2many_tags" invisible="'prepaid' not in context.get('type', '-')"/>
2765+ </field>
2766+ </field>
2767+</record>
2768+
2769+<!-- Form view for lines -->
2770+<record id="account_cutoff_line_form" model="ir.ui.view">
2771+ <field name="name">account.cutoff.line.prepaid.form</field>
2772+ <field name="model">account.cutoff.line</field>
2773+ <field name="inherit_id" ref="account_cutoff_base.account_cutoff_line_form"/>
2774+ <field name="arch" type="xml">
2775+ <field name="parent_id" position="after">
2776+ <field name="move_line_id" invisible="'prepaid' not in context.get('type', '-')"/>
2777+ <field name="move_date" invisible="'prepaid' not in context.get('type', '-')" />
2778+ <field name="invoice_id" invisible="'prepaid' not in context.get('type', '-')" />
2779+ </field>
2780+ <field name="name" position="after">
2781+ <field name="start_date" invisible="'prepaid' not in context.get('type', '-')"/>
2782+ <field name="end_date" invisible="'prepaid' not in context.get('type', '-')"/>
2783+ </field>
2784+ <field name="cutoff_amount" position="before">
2785+ <field name="total_days" invisible="'prepaid' not in context.get('type', '-')"/>
2786+ <field name="after_cutoff_days" invisible="'prepaid' not in context.get('type', '-')"/>
2787+ </field>
2788+ </field>
2789+</record>
2790+
2791+<!-- Tree view for lines -->
2792+<record id="account_cutoff_line_tree" model="ir.ui.view">
2793+ <field name="name">account.cutoff.line.prepaid.tree</field>
2794+ <field name="model">account.cutoff.line</field>
2795+ <field name="inherit_id" ref="account_cutoff_base.account_cutoff_line_tree"/>
2796+ <field name="arch" type="xml">
2797+ <field name="parent_id" position="after">
2798+ <field name="move_line_id" invisible="'prepaid' not in context.get('type', '-')"/>
2799+ </field>
2800+ <field name="analytic_account_code" position="after">
2801+ <field name="start_date" invisible="'prepaid' not in context.get('type', '-')"/>
2802+ <field name="end_date" invisible="'prepaid' not in context.get('type', '-')"/>
2803+ <field name="total_days" string="Days Total" invisible="'prepaid' not in context.get('type', '-')"/>
2804+ <field name="after_cutoff_days" string="Days after Cut-off" invisible="'prepaid' not in context.get('type', '-')"/>
2805+ </field>
2806+ </field>
2807+</record>
2808+
2809+
2810+<record id="account_cutoff_prepaid_expense_action" model="ir.actions.act_window">
2811+ <field name="name">Prepaid Expense</field>
2812+ <field name="res_model">account.cutoff</field>
2813+ <field name="view_type">form</field>
2814+ <field name="view_mode">tree,form</field>
2815+ <field name="domain">[('type', '=', 'prepaid_expense')]</field>
2816+ <field name="context">{'type': 'prepaid_expense'}</field>
2817+ <field name="help" type="html">
2818+ <p class="oe_view_nocontent_create">
2819+ Click to start preparing a new prepaid expense.
2820+ </p><p>
2821+ This view can be used by accountants in order to collect information about prepaid expenses based on start date and end date. It then allows to generate the corresponding cutoff journal entry in one click.
2822+ </p>
2823+ </field>
2824+</record>
2825+
2826+
2827+<menuitem id="account_cutoff_prepaid_expense_menu"
2828+ parent="account_cutoff_base.cutoff_menu"
2829+ action="account_cutoff_prepaid_expense_action"
2830+ sequence="25"/>
2831+
2832+
2833+<record id="account_cutoff_prepaid_revenue_action" model="ir.actions.act_window">
2834+ <field name="name">Prepaid Revenue</field>
2835+ <field name="res_model">account.cutoff</field>
2836+ <field name="view_type">form</field>
2837+ <field name="view_mode">tree,form</field>
2838+ <field name="domain">[('type', '=', 'prepaid_revenue')]</field>
2839+ <field name="context">{'type': 'prepaid_revenue'}</field>
2840+ <field name="help" type="html">
2841+ <p class="oe_view_nocontent_create">
2842+ Click to start preparing a new prepaid revenue.
2843+ </p><p>
2844+ This view can be used by accountants in order to collect information about prepaid revenues based on start date and end date. It then allows to generate the corresponding cutoff journal entry in one click.
2845+ </p>
2846+ </field>
2847+</record>
2848+
2849+
2850+<menuitem id="account_cutoff_prepaid_revenue_menu"
2851+ parent="account_cutoff_base.cutoff_menu"
2852+ action="account_cutoff_prepaid_revenue_action"
2853+ sequence="20"/>
2854+
2855+
2856+</data>
2857+</openerp>
2858
2859=== added file 'account_cutoff_prepaid/account_invoice_view.xml'
2860--- account_cutoff_prepaid/account_invoice_view.xml 1970-01-01 00:00:00 +0000
2861+++ account_cutoff_prepaid/account_invoice_view.xml 2013-12-24 15:32:24 +0000
2862@@ -0,0 +1,60 @@
2863+<?xml version="1.0" encoding="utf-8"?>
2864+
2865+<!--
2866+ Copyright (C) 2013 Akretion (http://www.akretion.com/)
2867+ @author Alexis de Lattre <alexis.delattre@akretion.com>
2868+ The licence is in the file __openerp__.py
2869+-->
2870+
2871+<openerp>
2872+<data>
2873+
2874+
2875+<record id="invoice_form" model="ir.ui.view">
2876+ <field name="name">prepaid.cutoff.invoice_form</field>
2877+ <field name="model">account.invoice</field>
2878+ <field name="inherit_id" ref="account.invoice_form" />
2879+ <field name="arch" type="xml">
2880+ <xpath expr="//field[@name='invoice_line']/tree/field[@name='account_analytic_id']" position="after">
2881+ <field name="start_date" />
2882+ <field name="end_date" />
2883+ </xpath>
2884+ <!-- Code to test the form view of invoice lines -->
2885+ <!--
2886+ <xpath expr="//field[@name='invoice_line']/tree" position="attributes">
2887+ <attribute name="editable"></attribute>
2888+ </xpath> -->
2889+ </field>
2890+</record>
2891+
2892+
2893+<record id="invoice_supplier_form" model="ir.ui.view">
2894+ <field name="name">prepaid.cutoff.invoice_supplier_form</field>
2895+ <field name="model">account.invoice</field>
2896+ <field name="inherit_id" ref="account.invoice_supplier_form" />
2897+ <field name="arch" type="xml">
2898+ <xpath expr="//field[@name='invoice_line']/tree/field[@name='account_analytic_id']" position="after">
2899+ <field name="start_date" />
2900+ <field name="end_date" />
2901+ </xpath>
2902+ </field>
2903+</record>
2904+
2905+
2906+<record id="view_invoice_line_form" model="ir.ui.view">
2907+ <field name="name">prepaid.cutoff.invoice_line_form</field>
2908+ <field name="model">account.invoice.line</field>
2909+ <field name="inherit_id" ref="account.view_invoice_line_form"/>
2910+ <field name="arch" type="xml">
2911+ <xpath expr="//field[@name='discount']/.." position="after">
2912+ <group name="start_end_dates">
2913+ <field name="start_date" />
2914+ <field name="end_date" />
2915+ </group>
2916+ </xpath>
2917+ </field>
2918+</record>
2919+
2920+
2921+</data>
2922+</openerp>
2923
2924=== added file 'account_cutoff_prepaid/account_view.xml'
2925--- account_cutoff_prepaid/account_view.xml 1970-01-01 00:00:00 +0000
2926+++ account_cutoff_prepaid/account_view.xml 2013-12-24 15:32:24 +0000
2927@@ -0,0 +1,53 @@
2928+<?xml version="1.0" encoding="utf-8"?>
2929+
2930+<!--
2931+ Copyright (C) 2013 Akretion (http://www.akretion.com/)
2932+ @author Alexis de Lattre <alexis.delattre@akretion.com>
2933+ The licence is in the file __openerp__.py
2934+-->
2935+
2936+<openerp>
2937+<data>
2938+
2939+
2940+<record id="view_move_line_form" model="ir.ui.view">
2941+ <field name="name">prepaid.cutoff.start.end.date.view_move_line_form</field>
2942+ <field name="model">account.move.line</field>
2943+ <field name="inherit_id" ref="account.view_move_line_form" />
2944+ <field name="arch" type="xml">
2945+ <field name="date_maturity" position="after">
2946+ <field name="start_date" />
2947+ <field name="end_date" />
2948+ </field>
2949+ </field>
2950+</record>
2951+
2952+
2953+<record id="view_move_line_form2" model="ir.ui.view">
2954+ <field name="name">prepaid.cutoff.start.end.date.view_move_line_form2</field>
2955+ <field name="model">account.move.line</field>
2956+ <field name="inherit_id" ref="account.view_move_line_form2" />
2957+ <field name="arch" type="xml">
2958+ <field name="date_maturity" position="after">
2959+ <field name="start_date" />
2960+ <field name="end_date" />
2961+ </field>
2962+ </field>
2963+</record>
2964+
2965+
2966+<record id="view_move_form" model="ir.ui.view">
2967+ <field name="name">prepaid.cutoff.start.end.date.view_move_form</field>
2968+ <field name="model">account.move</field>
2969+ <field name="inherit_id" ref="account.view_move_form" />
2970+ <field name="arch" type="xml">
2971+ <field name="date_maturity" position="after">
2972+ <field name="start_date" />
2973+ <field name="end_date" />
2974+ </field>
2975+ </field>
2976+</record>
2977+
2978+
2979+</data>
2980+</openerp>
2981
2982=== added file 'account_cutoff_prepaid/company.py'
2983--- account_cutoff_prepaid/company.py 1970-01-01 00:00:00 +0000
2984+++ account_cutoff_prepaid/company.py 2013-12-24 15:32:24 +0000
2985@@ -0,0 +1,37 @@
2986+# -*- encoding: utf-8 -*-
2987+##############################################################################
2988+#
2989+# Account Cut-off Prepaid module for OpenERP
2990+# Copyright (C) 2013 Akretion (http://www.akretion.com)
2991+# @author Alexis de Lattre <alexis.delattre@akretion.com>
2992+#
2993+# This program is free software: you can redistribute it and/or modify
2994+# it under the terms of the GNU Affero General Public License as
2995+# published by the Free Software Foundation, either version 3 of the
2996+# License, or (at your option) any later version.
2997+#
2998+# This program is distributed in the hope that it will be useful,
2999+# but WITHOUT ANY WARRANTY; without even the implied warranty of
3000+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
3001+# GNU Affero General Public License for more details.
3002+#
3003+# You should have received a copy of the GNU Affero General Public License
3004+# along with this program. If not, see <http://www.gnu.org/licenses/>.
3005+#
3006+##############################################################################
3007+
3008+
3009+from openerp.osv import orm, fields
3010+
3011+
3012+class res_company(orm.Model):
3013+ _inherit = 'res.company'
3014+
3015+ _columns = {
3016+ 'default_prepaid_revenue_account_id': fields.many2one(
3017+ 'account.account', 'Default Account for Prepaid Revenue',
3018+ domain=[('type', '<>', 'view'), ('type', '<>', 'closed')]),
3019+ 'default_prepaid_expense_account_id': fields.many2one(
3020+ 'account.account', 'Default Account for Prepaid Expense',
3021+ domain=[('type', '<>', 'view'), ('type', '<>', 'closed')]),
3022+ }
3023
3024=== added file 'account_cutoff_prepaid/company_view.xml'
3025--- account_cutoff_prepaid/company_view.xml 1970-01-01 00:00:00 +0000
3026+++ account_cutoff_prepaid/company_view.xml 2013-12-24 15:32:24 +0000
3027@@ -0,0 +1,27 @@
3028+<?xml version="1.0" encoding="utf-8"?>
3029+
3030+<!--
3031+ Copyright (C) 2013 Akretion (http://www.akretion.com/)
3032+ @author Alexis de Lattre <alexis.delattre@akretion.com>
3033+ The licence is in the file __openerp__.py
3034+-->
3035+
3036+<openerp>
3037+<data>
3038+
3039+
3040+<record id="view_company_form" model="ir.ui.view">
3041+ <field name="name">account.prepaid.cutoff.company.form</field>
3042+ <field name="model">res.company</field>
3043+ <field name="inherit_id" ref="account_cutoff_base.view_company_form" />
3044+ <field name="arch" type="xml">
3045+ <field name="default_cutoff_journal_id" position="after">
3046+ <field name="default_prepaid_revenue_account_id" />
3047+ <field name="default_prepaid_expense_account_id" />
3048+ </field>
3049+ </field>
3050+</record>
3051+
3052+
3053+</data>
3054+</openerp>
3055
3056=== added directory 'account_cutoff_prepaid/i18n'
3057=== added file 'account_cutoff_prepaid/i18n/account_cutoff_prepaid.pot'
3058--- account_cutoff_prepaid/i18n/account_cutoff_prepaid.pot 1970-01-01 00:00:00 +0000
3059+++ account_cutoff_prepaid/i18n/account_cutoff_prepaid.pot 2013-12-24 15:32:24 +0000
3060@@ -0,0 +1,242 @@
3061+# Translation of OpenERP Server.
3062+# This file contains the translation of the following modules:
3063+# * account_cutoff_prepaid
3064+#
3065+msgid ""
3066+msgstr ""
3067+"Project-Id-Version: OpenERP Server 7.0\n"
3068+"Report-Msgid-Bugs-To: \n"
3069+"POT-Creation-Date: 2013-12-24 15:26+0000\n"
3070+"PO-Revision-Date: 2013-12-24 15:26+0000\n"
3071+"Last-Translator: <>\n"
3072+"Language-Team: \n"
3073+"MIME-Version: 1.0\n"
3074+"Content-Type: text/plain; charset=UTF-8\n"
3075+"Content-Transfer-Encoding: \n"
3076+"Plural-Forms: \n"
3077+
3078+#. module: account_cutoff_prepaid
3079+#: field:account.cutoff.line,move_line_id:0
3080+msgid "Accout Move Line"
3081+msgstr ""
3082+
3083+#. module: account_cutoff_prepaid
3084+#: field:account.cutoff.line,end_date:0
3085+#: field:account.invoice.line,end_date:0
3086+#: field:account.move.line,end_date:0
3087+msgid "End Date"
3088+msgstr ""
3089+
3090+#. module: account_cutoff_prepaid
3091+#: help:product.template,must_have_dates:0
3092+msgid "If this option is active, the user will have to enter a Start Date and an End Date on the invoice lines that have this product."
3093+msgstr ""
3094+
3095+#. module: account_cutoff_prepaid
3096+#: field:product.template,must_have_dates:0
3097+msgid "Must Have Start and End Dates"
3098+msgstr ""
3099+
3100+#. module: account_cutoff_prepaid
3101+#: field:res.company,default_prepaid_expense_account_id:0
3102+msgid "Default Account for Prepaid Expense"
3103+msgstr ""
3104+
3105+#. module: account_cutoff_prepaid
3106+#: field:account.cutoff,source_journal_ids:0
3107+msgid "Source Journals"
3108+msgstr ""
3109+
3110+#. module: account_cutoff_prepaid
3111+#: field:account.cutoff.line,move_date:0
3112+msgid "Account Move Date"
3113+msgstr ""
3114+
3115+#. module: account_cutoff_prepaid
3116+#: code:addons/account_cutoff_prepaid/account.py:95
3117+#, python-format
3118+msgid "Missing Start Date for move line with Name '%s'."
3119+msgstr ""
3120+
3121+#. module: account_cutoff_prepaid
3122+#: code:addons/account_cutoff_prepaid/account.py:47
3123+#, python-format
3124+msgid "Missing Start Date for invoice line with Description '%s'."
3125+msgstr ""
3126+
3127+#. module: account_cutoff_prepaid
3128+#: field:account.cutoff.line,total_days:0
3129+msgid "Total Number of Days"
3130+msgstr ""
3131+
3132+#. module: account_cutoff_prepaid
3133+#: constraint:account.invoice.line:0
3134+#: constraint:account.move.line:0
3135+msgid "Error msg in raise"
3136+msgstr ""
3137+
3138+#. module: account_cutoff_prepaid
3139+#: model:ir.actions.act_window,name:account_cutoff_prepaid.account_cutoff_prepaid_expense_action
3140+#: model:ir.ui.menu,name:account_cutoff_prepaid.account_cutoff_prepaid_expense_menu
3141+msgid "Prepaid Expense"
3142+msgstr ""
3143+
3144+#. module: account_cutoff_prepaid
3145+#: model:ir.actions.act_window,name:account_cutoff_prepaid.account_cutoff_prepaid_revenue_action
3146+#: model:ir.ui.menu,name:account_cutoff_prepaid.account_cutoff_prepaid_revenue_menu
3147+msgid "Prepaid Revenue"
3148+msgstr ""
3149+
3150+#. module: account_cutoff_prepaid
3151+#: code:addons/account_cutoff_prepaid/account.py:101
3152+#, python-format
3153+msgid "Start Date should be before End Date for move line with Name '%s'."
3154+msgstr ""
3155+
3156+#. module: account_cutoff_prepaid
3157+#: model:ir.model,name:account_cutoff_prepaid.model_account_move_line
3158+msgid "Journal Items"
3159+msgstr ""
3160+
3161+#. module: account_cutoff_prepaid
3162+#: view:account.cutoff:0
3163+msgid "Re-Generate Lines"
3164+msgstr ""
3165+
3166+#. module: account_cutoff_prepaid
3167+#: model:ir.model,name:account_cutoff_prepaid.model_account_cutoff
3168+msgid "Account Cut-off"
3169+msgstr ""
3170+
3171+#. module: account_cutoff_prepaid
3172+#: field:res.company,default_prepaid_revenue_account_id:0
3173+msgid "Default Account for Prepaid Revenue"
3174+msgstr ""
3175+
3176+#. module: account_cutoff_prepaid
3177+#: model:ir.model,name:account_cutoff_prepaid.model_account_cutoff_line
3178+msgid "Account Cut-off Line"
3179+msgstr ""
3180+
3181+#. module: account_cutoff_prepaid
3182+#: sql_constraint:account.cutoff:0
3183+msgid "A cut-off of the same type already exists with this cut-off date !"
3184+msgstr ""
3185+
3186+#. module: account_cutoff_prepaid
3187+#: field:account.cutoff.line,after_cutoff_days:0
3188+msgid "Number of Days after Cut-off Date"
3189+msgstr ""
3190+
3191+#. module: account_cutoff_prepaid
3192+#: model:product.template,name:account_cutoff_prepaid.product_insurance_contrat_product_template
3193+msgid "Car Insurance"
3194+msgstr ""
3195+
3196+#. module: account_cutoff_prepaid
3197+#: code:addons/account_cutoff_prepaid/account.py:40
3198+#: code:addons/account_cutoff_prepaid/account.py:46
3199+#: code:addons/account_cutoff_prepaid/account.py:53
3200+#: code:addons/account_cutoff_prepaid/account.py:89
3201+#: code:addons/account_cutoff_prepaid/account.py:94
3202+#: code:addons/account_cutoff_prepaid/account.py:100
3203+#: code:addons/account_cutoff_prepaid/account.py:144
3204+#: code:addons/account_cutoff_prepaid/account_cutoff.py:85
3205+#: code:addons/account_cutoff_prepaid/account_cutoff.py:129
3206+#, python-format
3207+msgid "Error:"
3208+msgstr ""
3209+
3210+#. module: account_cutoff_prepaid
3211+#: model:ir.model,name:account_cutoff_prepaid.model_res_company
3212+msgid "Companies"
3213+msgstr ""
3214+
3215+#. module: account_cutoff_prepaid
3216+#: view:account.cutoff.line:0
3217+msgid "Days Total"
3218+msgstr ""
3219+
3220+#. module: account_cutoff_prepaid
3221+#: code:addons/account_cutoff_prepaid/account.py:54
3222+#, python-format
3223+msgid "Start Date should be before or be the same as End Date for invoice line with Description '%s'."
3224+msgstr ""
3225+
3226+#. module: account_cutoff_prepaid
3227+#: code:addons/account_cutoff_prepaid/account.py:145
3228+#, python-format
3229+msgid "Missing Start Date and End Date for invoice line with Product '%s' which has the property 'Must Have Start and End Dates'."
3230+msgstr ""
3231+
3232+#. module: account_cutoff_prepaid
3233+#: code:addons/account_cutoff_prepaid/account_cutoff.py:129
3234+#, python-format
3235+msgid "You should set at least one Source Journal."
3236+msgstr ""
3237+
3238+#. module: account_cutoff_prepaid
3239+#: code:addons/account_cutoff_prepaid/account.py:41
3240+#, python-format
3241+msgid "Missing End Date for invoice line with Description '%s'."
3242+msgstr ""
3243+
3244+#. module: account_cutoff_prepaid
3245+#: code:addons/account_cutoff_prepaid/account.py:90
3246+#, python-format
3247+msgid "Missing End Date for move line with Name '%s'."
3248+msgstr ""
3249+
3250+#. module: account_cutoff_prepaid
3251+#: model:ir.model,name:account_cutoff_prepaid.model_product_template
3252+msgid "Product Template"
3253+msgstr ""
3254+
3255+#. module: account_cutoff_prepaid
3256+#: model:ir.model,name:account_cutoff_prepaid.model_account_invoice_line
3257+msgid "Invoice Line"
3258+msgstr ""
3259+
3260+#. module: account_cutoff_prepaid
3261+#: model:ir.actions.act_window,help:account_cutoff_prepaid.account_cutoff_prepaid_expense_action
3262+msgid "<p class=\"oe_view_nocontent_create\">\n"
3263+" Click to start preparing a new prepaid expense.\n"
3264+" </p><p>\n"
3265+" This view can be used by accountants in order to collect information about prepaid expenses based on start date and end date. It then allows to generate the corresponding cutoff journal entry in one click.\n"
3266+" </p>\n"
3267+" "
3268+msgstr ""
3269+
3270+#. module: account_cutoff_prepaid
3271+#: model:ir.actions.act_window,help:account_cutoff_prepaid.account_cutoff_prepaid_revenue_action
3272+msgid "<p class=\"oe_view_nocontent_create\">\n"
3273+" Click to start preparing a new prepaid revenue.\n"
3274+" </p><p>\n"
3275+" This view can be used by accountants in order to collect information about prepaid revenues based on start date and end date. It then allows to generate the corresponding cutoff journal entry in one click.\n"
3276+" </p>\n"
3277+" "
3278+msgstr ""
3279+
3280+#. module: account_cutoff_prepaid
3281+#: field:account.cutoff.line,invoice_id:0
3282+#: model:ir.model,name:account_cutoff_prepaid.model_account_invoice
3283+msgid "Invoice"
3284+msgstr ""
3285+
3286+#. module: account_cutoff_prepaid
3287+#: field:account.cutoff.line,start_date:0
3288+#: field:account.invoice.line,start_date:0
3289+#: field:account.move.line,start_date:0
3290+msgid "Start Date"
3291+msgstr ""
3292+
3293+#. module: account_cutoff_prepaid
3294+#: view:account.cutoff.line:0
3295+msgid "Days after Cut-off"
3296+msgstr ""
3297+
3298+#. module: account_cutoff_prepaid
3299+#: view:product.template:0
3300+msgid "Sales Properties"
3301+msgstr ""
3302+
3303
3304=== added directory 'account_cutoff_prepaid/images'
3305=== added file 'account_cutoff_prepaid/images/prepaid_revenue_done.jpg'
3306Binary files account_cutoff_prepaid/images/prepaid_revenue_done.jpg 1970-01-01 00:00:00 +0000 and account_cutoff_prepaid/images/prepaid_revenue_done.jpg 2013-12-24 15:32:24 +0000 differ
3307=== added file 'account_cutoff_prepaid/images/prepaid_revenue_draft.jpg'
3308Binary files account_cutoff_prepaid/images/prepaid_revenue_draft.jpg 1970-01-01 00:00:00 +0000 and account_cutoff_prepaid/images/prepaid_revenue_draft.jpg 2013-12-24 15:32:24 +0000 differ
3309=== added file 'account_cutoff_prepaid/images/prepaid_revenue_journal_entry.jpg'
3310Binary files account_cutoff_prepaid/images/prepaid_revenue_journal_entry.jpg 1970-01-01 00:00:00 +0000 and account_cutoff_prepaid/images/prepaid_revenue_journal_entry.jpg 2013-12-24 15:32:24 +0000 differ
3311=== added file 'account_cutoff_prepaid/product.py'
3312--- account_cutoff_prepaid/product.py 1970-01-01 00:00:00 +0000
3313+++ account_cutoff_prepaid/product.py 2013-12-24 15:32:24 +0000
3314@@ -0,0 +1,36 @@
3315+# -*- encoding: utf-8 -*-
3316+##############################################################################
3317+#
3318+# Account Cut-off Prepaid module for OpenERP
3319+# Copyright (C) 2013 Akretion (http://www.akretion.com)
3320+# @author Alexis de Lattre <alexis.delattre@akretion.com>
3321+#
3322+# This program is free software: you can redistribute it and/or modify
3323+# it under the terms of the GNU Affero General Public License as
3324+# published by the Free Software Foundation, either version 3 of the
3325+# License, or (at your option) any later version.
3326+#
3327+# This program is distributed in the hope that it will be useful,
3328+# but WITHOUT ANY WARRANTY; without even the implied warranty of
3329+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
3330+# GNU Affero General Public License for more details.
3331+#
3332+# You should have received a copy of the GNU Affero General Public License
3333+# along with this program. If not, see <http://www.gnu.org/licenses/>.
3334+#
3335+##############################################################################
3336+
3337+
3338+from openerp.osv import orm, fields
3339+
3340+
3341+class product_template(orm.Model):
3342+ _inherit = 'product.template'
3343+
3344+ _columns = {
3345+ 'must_have_dates': fields.boolean(
3346+ 'Must Have Start and End Dates',
3347+ help="If this option is active, the user will have to enter "
3348+ "a Start Date and an End Date on the invoice lines that have "
3349+ "this product."),
3350+ }
3351
3352=== added file 'account_cutoff_prepaid/product_demo.xml'
3353--- account_cutoff_prepaid/product_demo.xml 1970-01-01 00:00:00 +0000
3354+++ account_cutoff_prepaid/product_demo.xml 2013-12-24 15:32:24 +0000
3355@@ -0,0 +1,25 @@
3356+<?xml version="1.0" encoding="utf-8"?>
3357+
3358+<!--
3359+ Copyright (C) 2013 Akretion (http://www.akretion.com/)
3360+ @author Alexis de Lattre <alexis.delattre@akretion.com>
3361+ The licence is in the file __openerp__.py
3362+-->
3363+
3364+<openerp>
3365+<data>
3366+
3367+<record id="product_insurance_contrat" model="product.product">
3368+ <field name="name">Car Insurance</field>
3369+ <field name="default_code">CARINSUR</field>
3370+ <field name="type">service</field>
3371+ <field name="categ_id" ref="product.product_category_5"/>
3372+ <field name="must_have_dates" eval="True" />
3373+ <field name="sale_ok" eval="True" />
3374+ <field name="purchase_ok" eval="True" />
3375+ <field name="list_price" eval="1200.0"/>
3376+ <field name="standard_price" eval="600.0"/>
3377+</record>
3378+
3379+</data>
3380+</openerp>
3381
3382=== added file 'account_cutoff_prepaid/product_view.xml'
3383--- account_cutoff_prepaid/product_view.xml 1970-01-01 00:00:00 +0000
3384+++ account_cutoff_prepaid/product_view.xml 2013-12-24 15:32:24 +0000
3385@@ -0,0 +1,40 @@
3386+<?xml version="1.0" encoding="utf-8"?>
3387+
3388+<!--
3389+ Copyright (C) 2013 Akretion (http://www.akretion.com/)
3390+ @author Alexis de Lattre <alexis.delattre@akretion.com>
3391+ The licence is in the file __openerp__.py
3392+-->
3393+
3394+<openerp>
3395+<data>
3396+
3397+<record id="product_normal_form_view" model="ir.ui.view">
3398+ <field name="name">add.must.have.dates.on.product.product.form</field>
3399+ <field name="model">product.product</field>
3400+ <field name="inherit_id" ref="account.product_normal_form_view" />
3401+ <field name="arch" type="xml">
3402+ <group name="properties" position="inside">
3403+ <group name="enable_dates">
3404+ <field name="must_have_dates" />
3405+ </group>
3406+ </group>
3407+ </field>
3408+</record>
3409+
3410+
3411+<record id="product_template_form_view" model="ir.ui.view">
3412+ <field name="name">add.must.have.dates.on.product.template.form</field>
3413+ <field name="model">product.template</field>
3414+ <field name="inherit_id" ref="account.product_template_form_view" />
3415+ <field name="arch" type="xml">
3416+ <separator string="Sales Properties" position="before">
3417+ <field name="must_have_dates" />
3418+ <newline />
3419+ </separator>
3420+ </field>
3421+</record>
3422+
3423+
3424+</data>
3425+</openerp>
3426
3427=== added directory 'account_cutoff_prepaid/static'
3428=== added directory 'account_cutoff_prepaid/static/src'
3429=== added directory 'account_cutoff_prepaid/static/src/img'
3430=== added file 'account_cutoff_prepaid/static/src/img/icon.png'
3431Binary files account_cutoff_prepaid/static/src/img/icon.png 1970-01-01 00:00:00 +0000 and account_cutoff_prepaid/static/src/img/icon.png 2013-12-24 15:32:24 +0000 differ

Subscribers

People subscribed via source and target branches