Merge lp:~sebastien.beau/c2c-financial-addons/c2c-financial-addons-fix-rule-m2m into lp:c2c-financial-addons

Proposed by Sébastien BEAU - http://www.akretion.com
Status: Superseded
Proposed branch: lp:~sebastien.beau/c2c-financial-addons/c2c-financial-addons-fix-rule-m2m
Merge into: lp:c2c-financial-addons
Diff against target: 3107 lines (+2882/-2)
41 files modified
account_credit_management/__init__.py (+28/-0)
account_credit_management/__openerp__.py (+47/-0)
account_credit_management/credit_management_account.py (+220/-0)
account_credit_management/credit_management_account_view.xml (+41/-0)
account_credit_management/credit_management_company.py (+28/-0)
account_credit_management/credit_management_company_view.xml (+15/-0)
account_credit_management/credit_management_demo.xml (+33/-0)
account_credit_management/credit_management_line.py (+181/-0)
account_credit_management/credit_management_line_view.xml (+145/-0)
account_credit_management/credit_management_partner.py (+36/-0)
account_credit_management/credit_management_partner_view.xml (+25/-0)
account_credit_management/credit_management_profile.py (+292/-0)
account_credit_management/credit_management_profile_view.xml (+118/-0)
account_credit_management/credit_management_run.py (+150/-0)
account_credit_management/credit_management_run_view.xml (+65/-0)
account_credit_management/data.xml (+173/-0)
account_credit_management/report/__init__.py (+1/-0)
account_credit_management/report/credit_management_summary.html.mako (+19/-0)
account_credit_management/report/credit_management_summary.py (+37/-0)
account_credit_management/report/report.xml (+12/-0)
account_credit_management/scenarios/credit_management/00_credit_management_param.feature (+23/-0)
account_credit_management/scenarios/credit_management/01_credit_management_partners.feature (+60/-0)
account_credit_management/scenarios/credit_management/credit_management_01_data.feature (+224/-0)
account_credit_management/scenarios/credit_management/credit_management_02_run.feature (+33/-0)
account_credit_management/scenarios/credit_management/credit_management_03_run.feature (+26/-0)
account_credit_management/scenarios/credit_management/step_definitions/credit_management.rb (+115/-0)
account_credit_management/scenarios/run_command.txt (+1/-0)
account_credit_management/security/ir.model.access.csv (+27/-0)
account_credit_management/wizard/__init__.py (+24/-0)
account_credit_management/wizard/credit_management_communication.py (+178/-0)
account_credit_management/wizard/credit_management_mailer.py (+64/-0)
account_credit_management/wizard/credit_management_mailer_view.xml (+44/-0)
account_credit_management/wizard/credit_management_marker.py (+83/-0)
account_credit_management/wizard/credit_management_marker_view.xml (+44/-0)
account_credit_management/wizard/credit_management_printer.py (+74/-0)
account_credit_management/wizard/credit_management_printer_view.xml (+47/-0)
account_fiscal_position_rule_m2m/fiscal_rules.py (+2/-2)
account_payment_ext/__init__.py (+32/-0)
account_payment_ext/__openerp__.py (+50/-0)
account_payment_ext/account_payment.py (+47/-0)
account_payment_ext/account_payment_view.xml (+18/-0)
To merge this branch: bzr merge lp:~sebastien.beau/c2c-financial-addons/c2c-financial-addons-fix-rule-m2m
Reviewer Review Type Date Requested Status
Guewen Baconnier @ Camptocamp Approve
Alexandre Fayolle - camptocamp Needs Fixing
Review via email: mp+129642@code.launchpad.net

This proposal has been superseded by a proposal from 2012-10-23.

Description of the change

FIX a bug

To post a comment you must log in.
Revision history for this message
Alexandre Fayolle - camptocamp (alexandre-fayolle-c2c) wrote :

The merge is huge for "a bug". Can you check you requested the merge on the right branch + describe the bug you're trying to fix (or link to a bug on the tracker)?

Thanks

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

Hi Sébastien,

Please create your merge proposal into lp:c2c-financial-addons/6.1

Thanks

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

Hi Sébastien,

I merged your fix (slightly modified) from the revision 90 in our 6.1 branch.

Thanks

Guewen

review: Approve

Unmerged revisions

90. By Sébastien BEAU - http://www.akretion.com

[FIX] account_fiscal_position_rule_m2m: fix wizard to generate rule from template

89. By Vincent Renaville@camptocamp

[ADD] account_payment ext

88. By Vincent Renaville@camptocamp

[MERGE] credit management

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== added directory 'account_credit_management'
=== added file 'account_credit_management/__init__.py'
--- account_credit_management/__init__.py 1970-01-01 00:00:00 +0000
+++ account_credit_management/__init__.py 2012-10-15 10:14:35 +0000
@@ -0,0 +1,28 @@
1# -*- coding: utf-8 -*-
2##############################################################################
3#
4# Author: Nicolas Bessi
5# Copyright 2012 Camptocamp SA
6#
7# This program is free software: you can redistribute it and/or modify
8# it under the terms of the GNU Affero General Public License as
9# published by the Free Software Foundation, either version 3 of the
10# License, or (at your option) any later version.
11#
12# This program is distributed in the hope that it will be useful,
13# but WITHOUT ANY WARRANTY; without even the implied warranty of
14# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15# GNU Affero General Public License for more details.
16#
17# You should have received a copy of the GNU Affero General Public License
18# along with this program. If not, see <http://www.gnu.org/licenses/>.
19#
20##############################################################################
21from . import credit_management_run
22from . import credit_management_line
23from . import credit_management_account
24from . import credit_management_partner
25from . import credit_management_profile
26from . import credit_management_company
27import wizard
28import report
029
=== added file 'account_credit_management/__openerp__.py'
--- account_credit_management/__openerp__.py 1970-01-01 00:00:00 +0000
+++ account_credit_management/__openerp__.py 2012-10-15 10:14:35 +0000
@@ -0,0 +1,47 @@
1# -*- coding: utf-8 -*-
2##############################################################################
3#
4# Author: Nicolas Bessi
5# Copyright 2012 Camptocamp SA
6#
7# This program is free software: you can redistribute it and/or modify
8# it under the terms of the GNU Affero General Public License as
9# published by the Free Software Foundation, either version 3 of the
10# License, or (at your option) any later version.
11#
12# This program is distributed in the hope that it will be useful,
13# but WITHOUT ANY WARRANTY; without even the implied warranty of
14# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15# GNU Affero General Public License for more details.
16#
17# You should have received a copy of the GNU Affero General Public License
18# along with this program. If not, see <http://www.gnu.org/licenses/>.
19#
20##############################################################################
21{'name' : 'Account Credit Management',
22 'version' : '0.1',
23 'author' : 'Camptocamp',
24 'maintainer': 'Camptocamp',
25 'category': 'Finance',
26 'complexity': "normal", # easy, normal, expert
27 'depends' : ['base', 'account', 'email_template', 'report_webkit'],
28 'description': """Credit control management TODO""",
29 'website': 'http://www.camptocamp.com',
30 'init_xml': ["data.xml"],
31 'update_xml': ["credit_management_line_view.xml",
32 "credit_management_account_view.xml",
33 "credit_management_partner_view.xml",
34 "credit_management_profile_view.xml",
35 "credit_management_run_view.xml",
36 "credit_management_company_view.xml",
37 "wizard/credit_management_mailer_view.xml",
38 "wizard/credit_management_marker_view.xml",
39 "wizard/credit_management_printer_view.xml",
40 "report/report.xml",
41 "security/ir.model.access.csv",],
42 #"credit_management_demo.xml"],
43 'demo_xml': ["credit_management_demo.xml"],
44 'tests': [],
45 'installable': True,
46 'license': 'AGPL-3',
47 'application': True}
048
=== added file 'account_credit_management/credit_management_account.py'
--- account_credit_management/credit_management_account.py 1970-01-01 00:00:00 +0000
+++ account_credit_management/credit_management_account.py 2012-10-15 10:14:35 +0000
@@ -0,0 +1,220 @@
1# -*- coding: utf-8 -*-
2##############################################################################
3#
4# Author: Nicolas Bessi
5# Copyright 2012 Camptocamp SA
6#
7# This program is free software: you can redistribute it and/or modify
8# it under the terms of the GNU Affero General Public License as
9# published by the Free Software Foundation, either version 3 of the
10# License, or (at your option) any later version.
11#
12# This program is distributed in the hope that it will be useful,
13# but WITHOUT ANY WARRANTY; without even the implied warranty of
14# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15# GNU Affero General Public License for more details.
16#
17# You should have received a copy of the GNU Affero General Public License
18# along with this program. If not, see <http://www.gnu.org/licenses/>.
19#
20##############################################################################
21from datetime import datetime
22import operator
23from openerp.osv.orm import Model, fields
24from openerp.tools.translate import _
25from openerp.addons.account_credit_management import credit_management_run
26
27class AccountAccount(Model):
28 """Add a link to a credit management profile on account account"""
29
30
31 def _check_account_type_compatibility(self, cursor, uid, acc_ids, context=None):
32 """We check that account is of type reconcile"""
33 if not isinstance(acc_ids, list):
34 acc_ids = [acc_ids]
35 for acc in self.browse(cursor, uid, acc_ids, context):
36 if acc.credit_profile_id and not acc.reconcile:
37 return False
38 return True
39
40 _inherit = "account.account"
41 _description = """Add a link to a credit profile"""
42 _columns = {'credit_profile_id': fields.many2one('credit.management.profile',
43 'Credit management profile',
44 help=("Define global credit profile"
45 "order is account partner invoice")),
46
47 'credit_management_line_ids': fields.one2many('credit.management.line',
48 'account_id',
49 string='Credit Lines',
50 readonly=True)}
51
52 _constraints = [(_check_account_type_compatibility,
53 _('You can not set a credit profile on a non reconciliable account'),
54 ['credit_profile_id'])]
55
56class AccountInvoice(Model):
57 """Add a link to a credit management profile on account account"""
58
59 _inherit = "account.invoice"
60 _description = """Add a link to a credit profile"""
61 _columns = {'credit_profile_id': fields.many2one('credit.management.profile',
62 'Credit management profile',
63 help=("Define global credit profile"
64 "order is account partner invoice")),
65
66 'credit_management_line_ids': fields.one2many('credit.management.line',
67 'account_id',
68 string='Credit Lines',
69 readonly=True)}
70
71 def action_move_create(self, cursor, uid, ids, context=None):
72 """We ensure writing of invoice id in move line because
73 Trigger field may not work without account_voucher addon"""
74 res = super(AccountInvoice, self).action_move_create(cursor, uid, ids, context=context)
75 for inv in self.browse(cursor, uid, ids, context=context):
76 if inv.move_id:
77 for line in inv.move_id.line_id:
78 line.write({'invoice_id': inv.id})
79 return res
80
81
82class AccountMoveLine(Model):
83 """Add a function that compute the residual amount using a follow up date
84 Add relation between move line and invoicex"""
85
86 _inherit = "account.move.line"
87 # Store fields has strange behavior with voucher module we had to overwrite invoice
88
89
90 # def _invoice_id(self, cursor, user, ids, name, arg, context=None):
91 # #Code taken from OpenERP account addon
92 # invoice_obj = self.pool.get('account.invoice')
93 # res = {}
94 # for line_id in ids:
95 # res[line_id] = False
96 # cursor.execute('SELECT l.id, i.id ' \
97 # 'FROM account_move_line l, account_invoice i ' \
98 # 'WHERE l.move_id = i.move_id ' \
99 # 'AND l.id IN %s',
100 # (tuple(ids),))
101 # invoice_ids = []
102 # for line_id, invoice_id in cursor.fetchall():
103 # res[line_id] = invoice_id
104 # invoice_ids.append(invoice_id)
105 # invoice_names = {False: ''}
106 # for invoice_id, name in invoice_obj.name_get(cursor, user, invoice_ids, context=context):
107 # invoice_names[invoice_id] = name
108 # for line_id in res.keys():
109 # invoice_id = res[line_id]
110 # res[line_id] = (invoice_id, invoice_names[invoice_id])
111 # return res
112
113 # def _get_invoice(self, cursor, uid, ids, context=None):
114 # result = set()
115 # for line in self.pool.get('account.invoice').browse(cursor, uid, ids, context=context):
116 # if line.move_id:
117 # ids = [x.id for x in line.move_id.line_id or []]
118 # return list(result)
119
120 # _columns = {'invoice_id': fields.function(_invoice_id, string='Invoice',
121 # type='many2one', relation='account.invoice',
122 # store={'account.invoice': (_get_invoice, ['move_id'], 20)})}
123
124 _columns = {'invoice_id': fields.many2one('account.invoice', 'Invoice')}
125
126 def _get_payment_and_credit_lines(self, moveline_array, lookup_date):
127 credit_lines = []
128 payment_lines = []
129 for line in moveline_array:
130 if self._should_exlude_line(line):
131 continue
132 if line.account_id.type == 'receivable' and line.debit:
133 credit_lines.append(line)
134 else:
135 if line.reconcile_partial_id:
136 payment_lines.append(line)
137 credit_lines.sort(key=operator.attrgetter('date'))
138 payment_lines.sort(key=operator.attrgetter('date'))
139 return (credit_lines, payment_lines)
140
141 def _validate_line_currencies(self, credit_lines):
142 """Raise an excpetion if there is lines with different currency"""
143 if len(credit_lines) == 0:
144 return True
145 currency = credit_lines[0].currency_id.id
146 if not all(obj.currency_id.id == currency for obj in credit_lines):
147 raise Exception('Not all line of move line are in the same currency')
148
149 def _get_value_amount(self, mv_line_br):
150 if mv_line_br.currency_id:
151 return mv_line_br.amount_currency
152 else:
153 return mv_line_br.debit - mv_line_br.credit
154
155 def _validate_partial(self, credit_lines):
156 if len(credit_lines) == 0:
157 return True
158 else:
159 line_with_partial = 0
160 for line in credit_lines:
161 if not line.reconcile_partial_id:
162 line_with_partial += 1
163 if line_with_partial and line_with_partial != len(credit_lines):
164 raise Exception('Can not compute credit line if multiple'
165 ' lines are not all linked to a partial')
166
167 def _get_applicable_payment_lines(self, credit_line, payment_lines):
168 applicable_payment = []
169 for pay_line in payment_lines:
170 if datetime.strptime(pay_line.date, "%Y-%m-%d").date() \
171 <= datetime.strptime(credit_line.date, "%Y-%m-%d").date():
172 applicable_payment.append(pay_line)
173 return applicable_payment
174
175 def _compute_partial_reconcile_residual(self, move_lines, lookup_date, move_id, memoizer):
176 """ Compute open amount of multiple credit lines linked to multiple payment lines"""
177 credit_lines, payment_lines = self._get_payment_and_credit_lines(move_lines, lookup_date, memoizer)
178 self._validate_line_currencies(credit_lines)
179 self._validate_line_currencies(payment_lines)
180 self._validate_partial(credit_lines)
181 # memoizer structure move_id : {move_line_id: open_amount}
182 # paymnent line and credit line are sorted by date
183 rest = 0.0
184 for credit_line in credit_lines:
185 applicable_payment = self._get_applicable_payment_lines(credit_line, payment_lines)
186 paid_amount = 0.0
187 for pay_line in applicable_payment:
188 paid_amount += self._get_value_amount(pay_line)
189 balance_amount = self._get_value_amount(credit_lines) - (paid_amount + rest)
190 memoizer[move_id][credit_line.id] = balance_amount
191 if balance_amount < 0.0:
192 rest = balance_amount
193 else:
194 rest = 0.0
195 return memoizer
196
197 def _compute_fully_open_amount(self, move_lines, lookup_date, move_id, memoizer):
198 for move_line in move_lines:
199 memoizer[move_id][move_line.id] = self._get_value_amount(move_line)
200 return memoizer
201
202
203 def _amount_residual_from_date(self, cursor, uid, mv_line_br, lookup_date, context=None):
204 """
205 Code from function _amount_residual of account/account_move_line.py does not take
206 in account mulitple line payment and reconciliation. We have to rewrite it
207 Code computes residual amount at lookup date for mv_line_br in entry
208 """
209 memoizer = credit_management_run.memoizers['credit_line_residuals']
210 move_id = mv_line_br.move_id.id
211 if mv_line_br.move_id.id in memoizer:
212 pass # get back value
213 else:
214 memoizer[move_id] = {}
215 move_lines = mv_line_br.move_id.line_id
216 if mv_line_br.reconcile_partial_id:
217 self._compute_partial_reconcile_residual(move_lines, lookup_date, move_id, memoizer)
218 else:
219 self._compute_fully_open_amount(move_lines, lookup_date, move_id, memoizer)
220 return memoizer[move_id][mv_line_br.id]
0221
=== added file 'account_credit_management/credit_management_account_view.xml'
--- account_credit_management/credit_management_account_view.xml 1970-01-01 00:00:00 +0000
+++ account_credit_management/credit_management_account_view.xml 2012-10-15 10:14:35 +0000
@@ -0,0 +1,41 @@
1<openerp>
2 <data>
3
4 <record id="account_followup_form_view" model="ir.ui.view">
5 <field name="name">account.followup.form.view</field>
6 <field name="model">account.account</field>
7 <field name="inherit_id" ref="account.view_account_form" />
8 <field name="type">form</field>
9 <field name="arch" type="xml">
10 <field name="reconcile" position="after">
11 <field name="credit_profile_id" groups="account_credit_management.group_account_credit_management_manager,account_credit_management.group_account_credit_management_user"/>
12 </field>
13 </field>
14 </record>
15
16 <act_window
17 id="act_account_credit_relation_relation"
18 name="Credit lines"
19 groups="account_credit_management.group_account_credit_management_manager,account_credit_management.group_account_credit_management_user"
20 domain="[('account_id', '=', active_id)]"
21 res_model="credit.management.line"
22 src_model="account.account"/>
23
24 <record id="invoice_followup_form_view" model="ir.ui.view">
25 <field name="name">invoice.followup.form.view</field>
26 <field name="model">account.invoice</field>
27 <field name="inherit_id" ref="account.invoice_form" />
28 <field name="type">form</field>
29 <field name="arch" type="xml">
30 <notebook position="inside">
31 <page string="Credit Management"
32 groups="account_credit_management.group_account_credit_management_manager,account_credit_management.group_account_credit_management_user,group_account_credit_management_info">
33 <field name="credit_profile_id"/>
34 <field name="credit_management_line_ids" colspan="4" nolabel="1"/>
35 </page>
36 </notebook>
37 </field>
38 </record>
39
40 </data>
41</openerp>
042
=== added file 'account_credit_management/credit_management_company.py'
--- account_credit_management/credit_management_company.py 1970-01-01 00:00:00 +0000
+++ account_credit_management/credit_management_company.py 2012-10-15 10:14:35 +0000
@@ -0,0 +1,28 @@
1# -*- coding: utf-8 -*-
2##############################################################################
3#
4# Author: Nicolas Bessi
5# Copyright 2012 Camptocamp SA
6#
7# This program is free software: you can redistribute it and/or modify
8# it under the terms of the GNU Affero General Public License as
9# published by the Free Software Foundation, either version 3 of the
10# License, or (at your option) any later version.
11#
12# This program is distributed in the hope that it will be useful,
13# but WITHOUT ANY WARRANTY; without even the implied warranty of
14# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15# GNU Affero General Public License for more details.
16#
17# You should have received a copy of the GNU Affero General Public License
18# along with this program. If not, see <http://www.gnu.org/licenses/>.
19#
20##############################################################################
21from openerp.osv.orm import Model, fields
22
23class ResCompany(Model):
24 _inherit = "res.company"
25
26 _columns = {"credit_management_tolerance": fields.float('Credit Tolerance')}
27
28 _defaults = {"credit_management_tolerance": 0.1}
029
=== added file 'account_credit_management/credit_management_company_view.xml'
--- account_credit_management/credit_management_company_view.xml 1970-01-01 00:00:00 +0000
+++ account_credit_management/credit_management_company_view.xml 2012-10-15 10:14:35 +0000
@@ -0,0 +1,15 @@
1<openerp>
2 <data>
3 <record id="credit_management_company_form" model="ir.ui.view">
4 <field name="name">credit.management.company.form</field>
5 <field name="model">res.company</field>
6 <field name="type">form</field>
7 <field name="inherit_id" ref="base.view_company_form"/>
8 <field name="arch" type="xml">
9 <field name="currency_id" position="after">
10 <field name="credit_management_tolerance"/>
11 </field>
12 </field>
13 </record>
14 </data>
15</openerp>
016
=== added file 'account_credit_management/credit_management_demo.xml'
--- account_credit_management/credit_management_demo.xml 1970-01-01 00:00:00 +0000
+++ account_credit_management/credit_management_demo.xml 2012-10-15 10:14:35 +0000
@@ -0,0 +1,33 @@
1<openerp>
2 <data>
3 <record id="a_recv_1" model="account.account">
4 <field name="code">X11002-a</field>
5 <field name="name">B2B Debtors - (test)</field>
6 <field ref="account.cas" name="parent_id"/>
7 <field name="type">receivable</field>
8 <field eval="True" name="reconcile"/>
9 <field name="credit_profile_id" ref="credit_management_no_follow"/>
10 <field name="user_type" ref="account.data_account_type_receivable"/>
11 </record>
12
13 <record id="a_recv_2" model="account.account">
14 <field name="code">X11002-b</field>
15 <field name="name">B2C Debtors - (test)</field>
16 <field ref="account.cas" name="parent_id"/>
17 <field name="type">receivable</field>
18 <field eval="True" name="reconcile"/>
19 <field name="credit_profile_id" ref="credit_management_2_time"/>
20 <field name="user_type" ref="account.data_account_type_receivable"/>
21 </record>
22
23 <record id="a_recv_3" model="account.account">
24 <field name="code">X11002-c</field>
25 <field name="name">New Debtors - (test)</field>
26 <field ref="account.cas" name="parent_id"/>
27 <field name="type">receivable</field>
28 <field eval="True" name="reconcile"/>
29 <field name="credit_profile_id" ref="credit_management_3_time"/>
30 <field name="user_type" ref="account.data_account_type_receivable"/>
31 </record>
32 </data>
33</openerp>
034
=== added file 'account_credit_management/credit_management_line.py'
--- account_credit_management/credit_management_line.py 1970-01-01 00:00:00 +0000
+++ account_credit_management/credit_management_line.py 2012-10-15 10:14:35 +0000
@@ -0,0 +1,181 @@
1# -*- coding: utf-8 -*-
2##############################################################################
3#
4# Author: Nicolas Bessi
5# Copyright 2012 Camptocamp SA
6#
7# This program is free software: you can redistribute it and/or modify
8# it under the terms of the GNU Affero General Public License as
9# published by the Free Software Foundation, either version 3 of the
10# License, or (at your option) any later version.
11#
12# This program is distributed in the hope that it will be useful,
13# but WITHOUT ANY WARRANTY; without even the implied warranty of
14# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15# GNU Affero General Public License for more details.
16#
17# You should have received a copy of the GNU Affero General Public License
18# along with this program. If not, see <http://www.gnu.org/licenses/>.
19#
20##############################################################################
21import logging
22
23from openerp.osv.orm import Model, fields
24import pooler
25#from datetime import datetime
26
27logger = logging.getLogger('credit.line.management')
28
29class CreditManagementLine (Model):
30 """A credit Management line decribe a line of amount due by a customer.
31 It is linked to all required financial account.
32 It has various state draft open to be send send. For more information about
33 usage please read __openerp__.py file"""
34
35 _name = "credit.management.line"
36 _description = """A credit Management line"""
37 _rec_name = "id"
38
39 _columns = {'date': fields.date('Controlling date', required=True),
40 # maturity date of related move line we do not use a related field in order to
41 # allow manual changes
42 'date_due': fields.date('Due date',
43 required=True,
44 readonly=True,
45 states={'draft': [('readonly', False)]}),
46
47 'date_sent': fields.date('Sent date',
48 readonly=True,
49 states={'draft': [('readonly', False)]}),
50
51 'state': fields.selection([('draft', 'Draft'),
52 ('to_be_sent', 'To be sent'),
53 ('sent', 'Done'),
54 ('error', 'Error'),
55 ('mail_error', 'Mailing Error')],
56 'State', required=True, readonly=True),
57
58 'canal': fields.selection([('manual', 'Manual'),
59 ('mail', 'Mail')],
60 'Canal', required=True,
61 readonly=True,
62 states={'draft': [('readonly', False)]}),
63
64 'invoice_id': fields.many2one('account.invoice', 'Invoice', readonly=True),
65 'partner_id': fields.many2one('res.partner', "Partner", required=True),
66 'amount_due': fields.float('Due Amount Tax inc.', required=True, readonly=True),
67 'balance_due': fields.float('Due balance', required=True, readonly=True),
68 'mail_message_id': fields.many2one('mail.message', 'Sent mail', readonly=True),
69
70 'move_line_id': fields.many2one('account.move.line', 'Move line',
71 required=True, readonly=True),
72
73 'account_id': fields.related('move_line_id', 'account_id', type='many2one',
74 relation='account.account', string='Account',
75 store=True, readonly=True),
76
77 'currency_id': fields.related('move_line_id', 'currency_id', type='many2one',
78 relation='res.currency', string='Currency',
79 store=True, readonly=True),
80
81 'company_id': fields.related('move_line_id', 'company_id', type='many2one',
82 relation='res.company', string='Company',
83 store=True, readonly=True),
84
85 # we can allow a manual change of profile in draft state
86 'profile_rule_id':fields.many2one('credit.management.profile.rule',
87 'Overdue Rule', required=True, readonly=True,
88 states={'draft': [('readonly', False)]}),
89
90 'profile_id': fields.related('profile_rule_id', 'profile_id', type='many2one',
91 relation='credit.management.profile', string='Profile',
92 store=True, readonly=True),
93
94 'level': fields.related('profile_rule_id', 'level', type='float',
95 relation='credit.management.profile', string='Level',
96 store=True, readonly=True),}
97
98
99 _defaults = {'state': 'draft'}
100
101 def _update_from_mv_line(self, cursor, uid, ids, mv_line_br, rule_br,
102 lookup_date, context=None):
103 """hook function to update line if required"""
104 context = context or {}
105 return []
106
107 def _create_from_mv_line(self, cursor, uid, ids, mv_line_br,
108 rule_br, lookup_date, context=None):
109 """Create credit line"""
110 acc_line_obj = self.pool.get('account.move.line')
111 context = context or {}
112 data_dict = {}
113 data_dict['date'] = lookup_date
114 data_dict['date_due'] = mv_line_br.date_maturity
115 data_dict['state'] = 'draft'
116 data_dict['canal'] = rule_br.canal
117 data_dict['invoice_id'] = (mv_line_br.invoice_id and mv_line_br.invoice_id.id
118 or False)
119 data_dict['partner_id'] = mv_line_br.partner_id.id
120 data_dict['amount_due'] = (mv_line_br.amount_currency or mv_line_br.debit
121 or mv_line_br.credit)
122 data_dict['balance_due'] = acc_line_obj._amount_residual_from_date(cursor, uid, mv_line_br,
123 lookup_date, context=context)
124 data_dict['profile_rule_id'] = rule_br.id
125 data_dict['company_id'] = mv_line_br.company_id.id
126 data_dict['move_line_id'] = mv_line_br.id
127 return [self.create(cursor, uid, data_dict)]
128
129
130 def create_or_update_from_mv_lines(self, cursor, uid, ids, lines,
131 rule_id, lookup_date, errors=None, context=None):
132 """Create or update line base on rules"""
133 context = context or {}
134 currency_obj = self.pool.get('res.currency')
135 rule_obj = self.pool.get('credit.management.profile.rule')
136 ml_obj = self.pool.get('account.move.line')
137 rule = rule_obj.browse(cursor, uid, rule_id, context)
138 current_lvl = rule.level
139 credit_line_ids = []
140 user = self.pool.get('res.users').browse(cursor, uid, uid)
141 tolerance_base = user.company_id.credit_management_tolerance
142 tolerance = {}
143 currency_ids = currency_obj.search(cursor, uid, [])
144
145 acc_line_obj = self.pool.get('account.move.line')
146 for c_id in currency_ids:
147 tmp = currency_obj.compute(cursor, uid, c_id,
148 user.company_id.currency_id.id, tolerance_base)
149 tolerance[c_id] = tmp
150
151 existings = self.search(cursor, uid, [('move_line_id', 'in', lines),
152 ('level', '=', current_lvl)])
153 db, pool = pooler.get_db_and_pool(cursor.dbname)
154 for line in ml_obj.browse(cursor, uid, lines, context):
155 # we want to create as many line as possible
156 local_cr = db.cursor()
157 try:
158 if line.id in existings:
159 # does nothing just a hook
160 credit_line_ids += self._update_from_mv_line(local_cr, uid, ids,
161 line, rule, lookup_date,
162 context=context)
163 else:
164 # as we use memoizer pattern this has almost no cost to get it
165 # multiple time
166 open_amount = acc_line_obj._amount_residual_from_date(cursor, uid, line,
167 lookup_date, context=context)
168
169 if open_amount > tolerance.get(line.currency_id.id, tolerance_base):
170 credit_line_ids += self._create_from_mv_line(local_cr, uid, ids,
171 line, rule, lookup_date,
172 context=context)
173 except Exception, exc:
174 logger.error(exc)
175 if errors:
176 errors.append(unicode(exc)) #obj-c common pattern
177 local_cr.rollback()
178 finally:
179 local_cr.commit()
180 local_cr.close()
181 return credit_line_ids
0182
=== added file 'account_credit_management/credit_management_line_view.xml'
--- account_credit_management/credit_management_line_view.xml 1970-01-01 00:00:00 +0000
+++ account_credit_management/credit_management_line_view.xml 2012-10-15 10:14:35 +0000
@@ -0,0 +1,145 @@
1<openerp>
2 <data>
3 <record id="credit_management_line_form" model="ir.ui.view">
4 <field name="name">credit.management.line.form</field>
5 <field name="model">credit.management.line</field>
6 <field name="type">form</field>
7 <field name="arch" type="xml">
8 <form>
9 <field name="date"/>
10 <field name="date_due"/>
11 <field name="date_sent"/>
12 <field name="level"/>
13 <field name="state"/>
14 <field name="canal"/>
15 <field name="invoice_id"/>
16 <field name="partner_id"/>
17 <!-- <field name="address_id" domain="[('partner_id', '=', partner_id)]"/> -->
18 <field name="amount_due"/>
19 <field name="balance_due"/>
20 <field name="currency_id"/>
21 <field name="move_line_id"/>
22 <field name="account_id"/>
23 <field name="profile_rule_id"/>
24 <field name="profile_id"/>
25 <field name="mail_message_id"/>
26 </form>
27 </field>
28 </record>
29
30 <record id="credit_management_line_search" model="ir.ui.view">
31 <field name="name">Credit lines</field>
32 <field name="model">credit.management.lines</field>
33 <field name="type">search</field>
34 <field name="arch" type="xml">
35 <search string="Search credit lines Items">
36 <group>
37 <filter icon="terp-document-new" string="New"
38 domain="[('state', '=', 'draft')]"
39 help="New lines"/>
40 <filter icon="terp-dolar_ok!" string="To be sent"
41 domain="[('state', '=', 'to_be_sent')]"
42 help="New lines"/>
43 <filter icon="terp-check" string="Sent"
44 domain="[('state', '=', 'sent')]"
45 help="New lines"/>
46 <separator orientation="vertical"/>
47 <filter icon="terp-gtk-stop" string="Error"
48 domain="[('state', 'in', ('error', 'mail_error'))]"
49 help="New lines"/>
50 <separator orientation="vertical"/>
51
52 <field name="date"/>
53 <field name="level"/>
54 <field name="partner_id"/>
55 <field name="account_id"/>
56 <newline/>
57 <field name="invoice_id"/>
58 <field name="profile_id"/>
59 <field name="profile_rule_id"/>
60 <field name ="canal" />
61 </group>
62 <newline/>
63
64 <group expand="0" string="Group By...">
65 <separator orientation="vertical"/>
66 <filter domain='[]' context="{'group_by': 'date'}"
67 icon="terp-go-month" string="Run date"/>
68 <separator orientation="vertical"/>
69 <filter domain='[]' context="{'group_by': 'level'}"
70 icon="terp-gtk-jump-to-rtl" string="Level"/>
71 <separator orientation="vertical"/>
72 <filter domain='[]' context="{'group_by': 'partner_id'}"
73 icon="terp-partner" string="Partner"/>
74 <separator orientation="vertical"/>
75 <filter domain='[]' context="{'group_by': 'account_id'}"
76 icon="terp-folder-green" string="Account"/>
77 <separator orientation="vertical"/>
78 <filter domain='[]' context="{'group_by': 'invoice_id'}"
79 icon="terp-document-new" string="Invoice"/>
80 <separator orientation="vertical"/>
81 <filter domain='[]' context="{'group_by': 'profile_id'}"
82 icon="terp-document-new" string="Credit Profile"/>
83 <separator orientation="vertical"/>
84 <filter domain='[]' context="{'group_by': 'profile_rule_id'}"
85 icon="terp-document-new" string="Credit Profile rule"/>
86 <separator orientation="vertical"/>
87 <filter domain='[]' context="{'group_by': 'canal'}"
88 icon="terp-document-new" string="Canal"/>
89 </group>
90 <newline/>
91 </search>
92 </field>
93 </record>
94
95 <record id="credit_management_line_tree" model="ir.ui.view">
96 <field name="name">credit.management.line.tree</field>
97 <field name="model">credit.management.line</field>
98 <field name="type">tree</field>
99 <field name="arch" type="xml">
100 <tree editable="bottom" colors="green:state == 'sent';red:state in ('error', 'mail_error');">
101 <field name="date"/>
102 <field name="date_due"/>
103 <field name="level"/>
104 <field name="state"/>
105 <field name="canal"/>
106 <field name="invoice_id"/>
107 <field name="partner_id"/>
108 <field name="amount_due"/>
109 <field name="balance_due"/>
110 <field name="currency_id"/>
111 <field name="move_line_id"/>
112 <field name="account_id"/>
113 <field name="profile_rule_id"/>
114 <field name="profile_id"/>
115 <field name="mail_message_id"/>
116 </tree>
117 </field>
118 </record>
119
120 <menuitem
121 name="Credit management"
122 parent="account.menu_finance_periodical_processing"
123 id="base_credit_management_menu"/>
124
125 <record model="ir.actions.act_window" id="credit_management_line_action">
126 <field name="name">Credit lines</field>
127 <field name="type">ir.actions.act_window</field>
128 <field name="res_model">credit.management.line</field>
129 <field name="domain"></field>
130 <field name="view_type">form</field>
131 <field name="view_mode">tree,form</field>
132 <field name="view_id" ref="credit_management_line_tree"/>
133 <field name="search_view_id" ref="credit_management_line_search"/>
134 </record>
135
136
137 <menuitem
138 name="Credit lines"
139 parent="base_credit_management_menu"
140 action="credit_management_line_action"
141 id="credit_management_line_action_menu"/>
142
143
144 </data>
145</openerp>
0146
=== added file 'account_credit_management/credit_management_partner.py'
--- account_credit_management/credit_management_partner.py 1970-01-01 00:00:00 +0000
+++ account_credit_management/credit_management_partner.py 2012-10-15 10:14:35 +0000
@@ -0,0 +1,36 @@
1# -*- coding: utf-8 -*-
2##############################################################################
3#
4# Author: Nicolas Bessi
5# Copyright 2012 Camptocamp SA
6#
7# This program is free software: you can redistribute it and/or modify
8# it under the terms of the GNU Affero General Public License as
9# published by the Free Software Foundation, either version 3 of the
10# License, or (at your option) any later version.
11#
12# This program is distributed in the hope that it will be useful,
13# but WITHOUT ANY WARRANTY; without even the implied warranty of
14# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15# GNU Affero General Public License for more details.
16#
17# You should have received a copy of the GNU Affero General Public License
18# along with this program. If not, see <http://www.gnu.org/licenses/>.
19#
20##############################################################################
21from openerp.osv.orm import Model, fields
22
23class ResPartner(Model):
24 """Add a link to a credit management profile on account account"""
25
26 _inherit = "res.partner"
27 _description = """Add a link to a credit profile"""
28 _columns = {'credit_profile_id': fields.many2one('credit.management.profile',
29 'Credit management profile',
30 help=("Define global credit profile"
31 "order is account partner invoice")),
32
33 'credit_management_line_ids': fields.one2many('credit.management.line',
34 'invoice_id',
35 string='Credit Lines',
36 readonly=True)}
037
=== added file 'account_credit_management/credit_management_partner_view.xml'
--- account_credit_management/credit_management_partner_view.xml 1970-01-01 00:00:00 +0000
+++ account_credit_management/credit_management_partner_view.xml 2012-10-15 10:14:35 +0000
@@ -0,0 +1,25 @@
1<openerp>
2<data>
3<record id="partner_followup_form_view" model="ir.ui.view">
4 <field name="name">partner.credit_management.form.view</field>
5 <field name="model">res.partner</field>
6 <field name="inherit_id" ref="base.view_partner_form" />
7 <field name="type">form</field>
8 <field name="arch" type="xml">
9 <field name="last_reconciliation_date" position="after">
10 <field name="credit_profile_id"
11 groups="account_credit_management.group_account_credit_management_manager,account_credit_management.group_account_credit_management_use"/>
12 </field>
13 </field>
14</record>
15
16 <act_window
17 id="act_partner_credit_relation_relation"
18 name="Credit lines"
19 groups="account_credit_management.group_account_credit_management_manager,account_credit_management.group_account_credit_management_user"
20 domain="[('partner_id', '=', active_id)]"
21 res_model="credit.management.line"
22 src_model="res.partner"/>
23
24</data>
25</openerp>
026
=== added file 'account_credit_management/credit_management_profile.py'
--- account_credit_management/credit_management_profile.py 1970-01-01 00:00:00 +0000
+++ account_credit_management/credit_management_profile.py 2012-10-15 10:14:35 +0000
@@ -0,0 +1,292 @@
1# -*- coding: utf-8 -*-
2##############################################################################
3#
4# Author: Nicolas Bessi
5# Copyright 2012 Camptocamp SA
6#
7# This program is free software: you can redistribute it and/or modify
8# it under the terms of the GNU Affero General Public License as
9# published by the Free Software Foundation, either version 3 of the
10# License, or (at your option) any later version.
11#
12# This program is distributed in the hope that it will be useful,
13# but WITHOUT ANY WARRANTY; without even the implied warranty of
14# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15# GNU Affero General Public License for more details.
16#
17# You should have received a copy of the GNU Affero General Public License
18# along with this program. If not, see <http://www.gnu.org/licenses/>.
19#
20##############################################################################
21from openerp.osv.orm import Model, fields
22from openerp.tools.translate import _
23
24class CreditManagementProfile(Model):
25 """Define a profile of reminder"""
26
27 _name = "credit.management.profile"
28 _description = """Define a reminder profile"""
29 _columns = {'name': fields.char('Name', required=True, size=128),
30
31 'profile_rule_ids' : fields.one2many('credit.management.profile.rule',
32 'profile_id',
33 'Profile Rules'),
34
35 'do_nothing' : fields.boolean('Do nothing',
36 help=('For profiling who should not '
37 'generate lines or are obsolete')),
38
39 'company_id' : fields.many2one('res.company', 'Company')
40 }
41
42
43 def _get_account_related_lines(self, cursor, uid, profile_id, lookup_date, lines, context=None):
44 """ We get all the lines related to accounts with given credit profile.
45 We try not to use direct SQL in order to respect security rules.
46 As we define the first set it is important, The date is used to do a prefilter.
47 !!!We take the asumption that only receivable lines have a maturity date
48 and account must be reconcillable"""
49 context = context or {}
50 move_l_obj = self.pool.get('account.move.line')
51 account_obj = self.pool.get('account.account')
52 acc_ids = account_obj.search(cursor, uid, [('credit_profile_id', '=', profile_id)])
53 if not acc_ids:
54 return lines
55 move_ids = move_l_obj.search(cursor, uid, [('account_id', 'in', acc_ids),
56 ('date_maturity', '<=', lookup_date),
57 ('reconcile_id', '=', False),
58 ('partner_id', '!=', False)])
59
60 lines += move_ids
61 return lines
62
63
64 def _get_sum_reduce_range(self, cursor, uid, profile_id, lookup_date, lines, model,
65 move_relation_field, context=None):
66 """ We get all the lines related to the model with given credit profile.
67 We also reduce from the global set (lines) the move line to be excluded.
68 We try not to use direct SQL in order to respect security rules.
69 As we define the first set it is important.
70 The profile relation field MUST be named credit_profile_id
71 and the model must have a relation
72 with account move line.
73 !!! We take the asumption that only receivable lines have a maturity date
74 and account must be reconcillable"""
75 # MARK possible place for a good optimisation
76 context = context or {}
77 my_obj = self.pool.get(model)
78 move_l_obj = self.pool.get('account.move.line')
79 add_obj_ids = my_obj.search(cursor, uid, [('credit_profile_id', '=', profile_id)])
80 if add_obj_ids:
81 add_lines = move_l_obj.search(cursor, uid, [(move_relation_field, 'in', add_obj_ids),
82 ('date_maturity', '<=', lookup_date),
83 ('partner_id', '!=', False),
84 ('reconcile_id', '=', False)])
85 lines = list(set(lines + add_lines))
86 # we get all the lines that must be excluded at partner_level
87 # from the global set (even the one included at account level)
88 neg_obj_ids = my_obj.search(cursor, uid, [('credit_profile_id', '!=', profile_id),
89 ('credit_profile_id', '!=', False)])
90 if neg_obj_ids:
91 # should we add ('id', 'in', lines) in domain ? it may give a veeery long SQL...
92 neg_lines = move_l_obj.search(cursor, uid, [(move_relation_field, 'in', neg_obj_ids),
93 ('date_maturity', '<=', lookup_date),
94 ('partner_id', '!=', False),
95 ('reconcile_id', '=', False)])
96 if neg_lines:
97 lines = list(set(lines) - set(neg_lines))
98 return lines
99
100
101 def _get_partner_related_lines(self, cursor, uid, profile_id, lookup_date, lines, context=None):
102 return self._get_sum_reduce_range(cursor, uid, profile_id, lookup_date, lines,
103 'res.partner', 'partner_id', context=context)
104
105
106 def _get_invoice_related_lines(self, cursor, uid, profile_id, lookup_date, lines, context=None):
107 return self._get_sum_reduce_range(cursor, uid, profile_id, lookup_date, lines,
108 'account.invoice', 'invoice', context=context)
109
110
111 def _get_moves_line_to_process(self, cursor, uid, profile_id, lookup_date, context=None):
112 """Retrive all the move line to be procces for current profile.
113 This function is planned to be use only on one id.
114 Priority of inclustion, exlusion is account, partner, invoice"""
115 context = context or {}
116 lines = []
117 if isinstance(profile_id, list):
118 profile_id = profile_id[0]
119 # order of call MUST be respected priority is account, partner, invoice
120 lines = self._get_account_related_lines(cursor, uid, profile_id,
121 lookup_date, lines, context=context)
122 lines = self._get_partner_related_lines(cursor, uid, profile_id,
123 lookup_date, lines, context=context)
124 lines = self._get_invoice_related_lines(cursor, uid, profile_id,
125 lookup_date, lines, context=context)
126 return lines
127
128 def _check_lines_profiles(self, cursor, uid, profile_id, lines, context=None):
129 """ Check if there is credit line related to same move line but
130 related to an other profile"""
131 context = context or {}
132 if not lines:
133 return []
134 if isinstance(profile_id, list):
135 profile_id = profile_id[0]
136 cursor.execute("SELECT move_line_id FROM credit_management_line"
137 " WHERE profile_id != %s and move_line_id in %s",
138 (profile_id, tuple(lines)))
139 res = cursor.fetchall()
140 if res:
141 return [x[0] for x in res]
142 else:
143 return []
144
145
146
147class CreditManagementProfileRule (Model):
148 """Define a profile rule. A rule allows to determine if
149 a move line is due and the level of overdue of the line"""
150
151 _name = "credit.management.profile.rule"
152 _order = 'level'
153 _description = """A credit management profile rule"""
154 _columns = {'profile_id': fields.many2one('credit.management.profile',
155 'Related Policy', required=True),
156 'name': fields.char('Name', size=128, required=True),
157 'level': fields.float('level', required=True),
158
159 'computation_mode': fields.selection([('net_days', 'Due date'),
160 ('end_of_month', 'Due Date: end of Month'),
161 ('previous_date', 'Previous reminder')],
162 'Compute mode',
163 required=True),
164
165 'delay_days': fields.integer('Delay in day', required='True'),
166 'mail_template_id': fields.many2one('email.template', 'Mail template',
167 required=True),
168 'canal': fields.selection([('manual', 'Manual'),
169 ('mail', 'Mail')],
170 'Canal', required=True),
171 'custom_text': fields.text('Custom message', required=True, translate=True),
172 }
173
174
175 def _check_level_mode(self, cursor, uid, rids, context=None):
176 """We check that the smallest level is not based
177 on a rule using previous_date mode"""
178 if not isinstance(rids, list):
179 rids = [rids]
180 for rule in self.browse(cursor, uid, rids, context):
181 smallest_rule_id = self.search(cursor, uid, [('profile_id', '=', rule.profile_id.id)],
182 order='level asc', limit=1, context=context)
183 smallest_rule = self.browse(cursor, uid, smallest_rule_id[0], context)
184 if smallest_rule.computation_mode == 'previous_date':
185 return False
186 return True
187
188
189
190 _sql_constraint = [('unique level',
191 'UNIQUE (profile_id, level)',
192 'Level must be unique per profile')]
193
194 _constraints = [(_check_level_mode,
195 'The smallest level can not be of type Previous reminder',
196 ['level'])]
197
198 def _is_first_level(self, cursor, uid, rule_br, context=None):
199 """Check if rule has the smallest priority"""
200 first_rule = self.search(cursor, uid, [('profile_id', '=', rule_br.profile_id.id)],
201 order='level asc', limit=1, context=context)
202 return first_rule[0] == rule_br.id
203 # ----- time related functions ---------
204
205 def _net_days_get_boundary(self):
206 return " (mv_line.date_maturity + %(delay)s)::date <= date(%(lookup_date)s)"
207
208 def _end_of_month_get_boundary(self):
209 return ("(date_trunc('MONTH', (mv_line.date_maturity + %(delay)s))+INTERVAL '1 MONTH - 1 day')::date"
210 "<= date(%(lookup_date)s)")
211
212 def _previous_date_get_boundary(self):
213 return "(cr_line.date + %(delay)s)::date <= date(%(lookup_date)s)"
214
215 def _get_sql_date_boundary_for_computation_mode(self, cursor, uid, rule_br, lookup_date, context=None):
216 """Return a where clauses statement for the given
217 lookup date and computation mode of the rule"""
218 fname = "_%s_get_boundary" % (rule_br.computation_mode,)
219 if hasattr(self, fname):
220 fnc = getattr(self, fname)
221 return fnc()
222 else:
223 raise NotImplementedError(_('Can not get function for computation mode: '
224 '%s is not implemented') % (fname,))
225
226 # -----------------------------------------
227
228 def _get_first_level_lines(self, cursor, uid, rule_br, lookup_date, lines, context=None):
229 if not lines:
230 return []
231 """Retrieve all the line that are linked to a frist level rules.
232 We use Raw SQL for perf. Security rule where applied in
233 profile object when line where retrieved"""
234 sql = ("SELECT DISTINCT mv_line.id\n"
235 " FROM account_move_line mv_line\n"
236 " WHERE mv_line.id in %(line_ids)s\n"
237 " AND NOT EXISTS (SELECT cr_line.id from credit_management_line cr_line\n"
238 " WHERE cr_line.move_line_id = mv_line.id)")
239 sql += " AND" + self._get_sql_date_boundary_for_computation_mode(cursor,
240 uid, rule_br,
241 lookup_date, context)
242 data_dict = {'lookup_date': lookup_date, 'line_ids': tuple(lines),
243 'delay': rule_br.delay_days}
244
245 cursor.execute(sql, data_dict)
246 res = cursor.fetchall()
247 if not res:
248 return []
249 return [x[0] for x in res]
250
251
252 def _get_other_level_lines(self, cursor, uid, rule_br, lookup_date, lines, context=None):
253 # We filter line that have a level smaller than current one
254 # TODO if code fits need refactor _get_first_level_lines and _get_other_level_lines
255 # Code is not DRY
256 if not lines:
257 return []
258 sql = ("SELECT mv_line.id\n"
259 " FROM account_move_line mv_line\n"
260 " JOIN credit_management_line cr_line\n"
261 " ON (mv_line.id = cr_line.move_line_id)\n"
262 " WHERE cr_line.id = (SELECT credit_management_line.id FROM credit_management_line\n"
263 " WHERE credit_management_line.move_line_id = mv_line.id\n"
264 " ORDER BY credit_management_line.level desc limit 1)\n"
265 " AND cr_line.level < %(level)s\n"
266 " AND mv_line.id in %(line_ids)s\n")
267 sql += " AND " + self._get_sql_date_boundary_for_computation_mode(cursor,
268 uid, rule_br,
269 lookup_date, context)
270 data_dict = {'lookup_date': lookup_date, 'line_ids': tuple(lines),
271 'delay': rule_br.delay_days, 'level': rule_br.level}
272
273 cursor.execute(sql, data_dict)
274 res = cursor.fetchall()
275 if not res:
276 return []
277 return [x[0] for x in res]
278
279 def get_rule_lines(self, cursor, uid, rule_id, lookup_date, lines, context=None):
280 """get all move lines in entry lines that match the current rule"""
281 if isinstance(rule_id, list):
282 rule_id = rule_id[0]
283 matching_lines = []
284 rule = self.browse(cursor, uid, rule_id, context=context)
285 if self._is_first_level(cursor, uid, rule):
286 matching_lines += self._get_first_level_lines(cursor, uid, rule, lookup_date,
287 lines, context=context)
288 else:
289 matching_lines += self._get_other_level_lines(cursor, uid, rule, lookup_date,
290 lines, context=context)
291
292 return matching_lines
0293
=== added file 'account_credit_management/credit_management_profile_view.xml'
--- account_credit_management/credit_management_profile_view.xml 1970-01-01 00:00:00 +0000
+++ account_credit_management/credit_management_profile_view.xml 2012-10-15 10:14:35 +0000
@@ -0,0 +1,118 @@
1<openerp>
2 <data>
3
4 <record id="credit_management_profile_form" model="ir.ui.view">
5 <field name="name">credit.management.profile.form</field>
6 <field name="model">credit.management.profile</field>
7 <field name="type">form</field>
8 <field name="arch" type="xml">
9 <form> <!-- editable="bottom" -->
10 <field name="name"/>
11 <field name="do_nothing"/>
12 <field name="company_id"/>
13 <notebook colspan="4">
14 <page string="Rules">
15 <field name="profile_rule_ids" colspan="4" >
16 <tree editable="bottom">
17 <field name="name"/>
18 <field name="level"/>
19 <field name="canal"/>
20 <field name="delay_days"/>
21 <field name="computation_mode"/>
22 <field name="mail_template_id"/>
23 </tree>
24 <form>
25 <field name="name"/>
26 <notebook colspan="4">
27 <page string="Delay Setting">
28 <field name="level"/>
29 <field name="canal"/>
30 <field name="delay_days"/>
31 <field name="computation_mode"/>
32 </page>
33 <page string="Mail and reporting">
34 <field name="mail_template_id"/>
35 <field name="custom_text"/>
36 </page>
37 </notebook>
38 </form>
39 </field>
40 </page>
41 </notebook>
42 </form>
43 </field>
44 </record>
45
46 <record id="credit_management_profile_tree" model="ir.ui.view">
47 <field name="name">credit.management.profile.tree</field>
48 <field name="model">credit.management.profile</field>
49 <field name="type">tree</field>
50 <field name="arch" type="xml">
51 <tree> <!-- editable="bottom" -->
52 <field name="name"/>
53 <field name="do_nothing"/>
54 </tree>
55 </field>
56 </record>
57
58 <menuitem
59 name="Credit management configuration"
60 parent="account.menu_finance_configuration"
61 id="base_credit_management_configuration_menu"/>
62
63 <record model="ir.actions.act_window" id="credit_profile_configuration_action">
64 <field name="name">Credit profiles</field>
65 <field name="type">ir.actions.act_window</field>
66 <field name="res_model">credit.management.profile</field>
67 <field name="domain"></field>
68 <field name="view_type">form</field>
69 <field name="view_mode">tree,form</field>
70 <field name="view_id" ref="credit_management_profile_tree"/>
71 </record>
72
73 <menuitem
74 name="Credit profiles"
75 parent="base_credit_management_configuration_menu"
76 action="credit_profile_configuration_action"
77 id="credit_profile_configuration_action_menu"/>
78
79 <record id="credit_mangement_profile_rule_form" model="ir.ui.view">
80 <field name="name">credit.mangement.profile.rule.form</field>
81 <field name="model">credit.management.profile.rule</field>
82 <field name="type">form</field>
83 <field name="arch" type="xml">
84 <form> <!-- editable="bottom" -->
85 <field name="name"/>
86 <notebook colspan="4">
87 <page string="Delay Setting">
88 <field name="level"/>
89 <field name="canal"/>
90 <field name="delay_days"/>
91 <field name="computation_mode"/>
92 </page>
93 <page string="Mail and reporting">
94 <field name="mail_template_id"/>
95 <field name="custom_text"/>
96 </page>
97 </notebook>
98 </form>
99 </field>
100 </record>
101
102 <record id="credit_management_profile_rule_tree" model="ir.ui.view">
103 <field name="name">credit.management.profile.rule.tree</field>
104 <field name="model">credit.management.profile.rule</field>
105 <field name="type">tree</field>
106 <field name="arch" type="xml">
107 <tree editable="bottom">
108 <field name="name"/>
109 <field name="level"/>
110 <field name="canal"/>
111 <field name="delay_days"/>
112 <field name="computation_mode"/>
113 <field name="mail_template_id"/>
114 </tree>
115 </field>
116 </record>
117 </data>
118</openerp>
0119
=== added file 'account_credit_management/credit_management_run.py'
--- account_credit_management/credit_management_run.py 1970-01-01 00:00:00 +0000
+++ account_credit_management/credit_management_run.py 2012-10-15 10:14:35 +0000
@@ -0,0 +1,150 @@
1# -*- coding: utf-8 -*-
2##############################################################################
3#
4# Author: Nicolas Bessi
5# Copyright 2012 Camptocamp SA
6#
7# This program is free software: you can redistribute it and/or modify
8# it under the terms of the GNU Affero General Public License as
9# published by the Free Software Foundation, either version 3 of the
10# License, or (at your option) any later version.
11#
12# This program is distributed in the hope that it will be useful,
13# but WITHOUT ANY WARRANTY; without even the implied warranty of
14# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15# GNU Affero General Public License for more details.
16#
17# You should have received a copy of the GNU Affero General Public License
18# along with this program. If not, see <http://www.gnu.org/licenses/>.
19#
20##############################################################################
21import sys
22import traceback
23import logging
24
25from openerp.osv.orm import Model, fields
26from openerp.tools.translate import _
27from openerp.osv.osv import except_osv
28
29logger = logging.getLogger('Credit management run')
30
31memoizers = {}
32
33
34class CreditManagementRun(Model):
35 """Credit management run generate all credit management lines and reject"""
36
37 _name = "credit.management.run"
38 _rec_name = 'date'
39 _description = """Credit management line generator"""
40 _columns = {'date': fields.date('Lookup date', required=True),
41 'profile_ids': fields.many2many('credit.management.profile',
42 rel="credit_run_profile_rel",
43 string='Profiles',
44 readonly=True,
45 help="If nothing set all profile will be used",
46
47 states={'draft': [('readonly', False)]}),
48
49 'report': fields.text('Report', readonly=True),
50
51 'state': fields.selection([('draft', 'Draft'),
52 ('running', 'Running'),
53 ('done', 'Done'),
54 ('error', 'Error')],
55 string='State',
56 required=True,
57 readonly=True),
58
59 'manual_ids': fields.many2many('account.move.line',
60 rel="credit_runreject_rel",
61 string='Line to be handled manually',
62 readonly=True),
63 }
64
65 _defaults = {'state': 'draft'}
66
67 def check_run_date(self, cursor, uid, ids, lookup_date, context=None):
68 """Ensure that there is no credit line in the future using lookup_date"""
69 line_obj = self.pool.get('credit.management.line')
70 lines = line_obj.search(cursor, uid, [('date', '>', lookup_date)],
71 order='date DESC', limit=1)
72 if lines:
73 line = line_obj.browse(cursor, uid, lines[0])
74 raise except_osv(_('A run was already executed in a greater date'),
75 _('Run date should be >= %s') % (line.date))
76
77
78 def _generate_credit_lines(self, cursor, uid, run_id, context=None):
79 """ Generate credit line. Function can be a little dryer but
80 it does almost noting, initalise variable maange error and call
81 real know how method"""
82 memoizers['credit_line_residuals'] = {}
83 cr_line_obj = self.pool.get('credit.management.line')
84 if isinstance(run_id, list):
85 run_id = run_id[0]
86 run = self.browse(cursor, uid, run_id, context=context)
87 errors = []
88 manualy_managed_lines = [] #line who changed profile
89 credit_line_ids = [] # generated lines
90 run.check_run_date(run.date, context=context)
91 profile_ids = run.profile_ids
92 if not profile_ids:
93 profile_obj = self.pool.get('credit.management.profile')
94 profile_ids_ids = profile_obj.search(cursor, uid, [])
95 profile_ids = profile_obj.browse(cursor, uid, profile_ids_ids)
96 for profile in profile_ids:
97 if profile.do_nothing:
98 continue
99 try:
100 lines = profile._get_moves_line_to_process(run.date, context=context)
101 tmp_manual = profile._check_lines_profiles(lines, context=context)
102 lines = list(set(lines) - set(tmp_manual))
103 manualy_managed_lines += tmp_manual
104 if not lines:
105 continue
106 # profile rules are sorted by level so iteration is in the correct order
107 for rule in profile.profile_rule_ids:
108 rule_lines = rule.get_rule_lines(run.date, lines)
109 #only this write action own a separate cursor
110 credit_line_ids += cr_line_obj.create_or_update_from_mv_lines(cursor, uid, [],
111 rule_lines, rule.id,
112 run.date, errors=errors,
113 context=context)
114 lines = list(set(lines) - set(rule_lines))
115 except Exception, exc:
116 cursor.rollback()
117 error_type, error_value, trbk = sys.exc_info()
118 st = "Error: %s\nDescription: %s\nTraceback:" % (error_type.__name__, error_value)
119 st += ''.join(traceback.format_tb(trbk, 30))
120 logger.error(st)
121 self.write(cursor, uid, [run.id], {'report':st, 'state': 'error'})
122 return False
123 vals = {'report': u"Number of generated lines : %s \n" % (len(credit_line_ids),),
124 'state': 'done',
125 'manual_ids': [(6, 0, manualy_managed_lines)]}
126 if errors:
127 vals['report'] += u"Following line generation errors appends:"
128 vals['report'] += u"----\n".join(errors)
129 vals['state'] = 'done'
130 run.write(vals)
131 # lines will correspond to line that where not treated
132 return lines
133
134
135
136 def generate_credit_lines(self, cursor, uid, run_id, context=None):
137 """Generate credit management lines"""
138 context = context or {}
139 # we do a little magical tips in order to ensure non concurrent run
140 # of the function generate_credit_lines
141 try:
142 cursor.execute('SELECT id FROM credit_management_run'
143 ' LIMIT 1 FOR UPDATE NOWAIT' )
144 except Exception, exc:
145 cursor.rollback()
146 raise except_osv(_('A credit management run is allready running'
147 ' in background please try later'),
148 str(exc))
149 # in case of exception openerp will do a rollback for us and free the lock
150 return self._generate_credit_lines(cursor, uid, run_id, context)
0151
=== added file 'account_credit_management/credit_management_run_view.xml'
--- account_credit_management/credit_management_run_view.xml 1970-01-01 00:00:00 +0000
+++ account_credit_management/credit_management_run_view.xml 2012-10-15 10:14:35 +0000
@@ -0,0 +1,65 @@
1<openerp>
2 <data>
3
4 <record id="credit_management_run_tree" model="ir.ui.view">
5 <field name="name">credit.management.run.tree</field>
6 <field name="model">credit.management.run</field>
7 <field name="type">tree</field>
8 <field name="arch" type="xml">
9 <tree> <!-- editable="bottom" -->
10 <field name="date"/>
11 <field name="state"/>
12 </tree>
13 </field>
14 </record>
15
16 <record id="credit_management_run_form" model="ir.ui.view">
17 <field name="name">credit.management.run.form</field>
18 <field name="model">credit.management.run</field>
19 <field name="type">form</field>
20 <field name="arch" type="xml">
21 <form> <!-- editable="bottom" -->
22 <field name="date"/>
23 <newline/>
24 <notebook colspan="4">
25 <page string="Profile">
26 <field name="profile_ids" colspan="4" nolabel="1"/>
27 </page>
28 <page string="Report and Errors">
29 <field name="report" colspan="4" nolabel="1"/>
30 <separator string="Move lines To be treated manually"/>
31 <field name="manual_ids" colspan="4" nolabel="1"/>
32 </page>
33 </notebook>
34 <group col="3" colspan="4">
35 <button name="generate_credit_lines"
36 string="Compute credit lines"
37 colspan="1"
38 type="object" icon="gtk-execute"
39 attrs="{'invisible': [('state', '!=', 'draft')]}"/>
40 </group>
41 <field name="state"/>
42 </form>
43 </field>
44 </record>
45
46
47 <record model="ir.actions.act_window" id="credit_management_run">
48 <field name="name">Credit management run</field>
49 <field name="type">ir.actions.act_window</field>
50 <field name="res_model">credit.management.run</field>
51 <field name="domain"></field>
52 <field name="view_type">form</field>
53 <field name="view_mode">tree,form</field>
54 <field name="view_id" ref="credit_management_run_tree"/>
55 </record>
56
57
58 <menuitem
59 name="Credit management run"
60 parent="base_credit_management_menu"
61 action="credit_management_run"
62 id="credit_management_run_menu"/>
63
64 </data>
65</openerp>
066
=== added file 'account_credit_management/data.xml'
--- account_credit_management/data.xml 1970-01-01 00:00:00 +0000
+++ account_credit_management/data.xml 2012-10-15 10:14:35 +0000
@@ -0,0 +1,173 @@
1<openerp>
2 <data noupdate="1">
3 <!--Email template -->
4 <record id="email_template_credit_management_base" model="email.template">
5 <field name="name">Credit Management demo mail</field>
6 <field name="email_from">noreply@localhost</field>
7 <field name="subject">Credit Management Invoice (${object.current_profile_rule.level or 'n/a' })</field>
8 <field name="email_to">${object.get_mail() or ''}</field>
9 <field name="model_id" ref="model_credit_management_communication"/>
10 <field name="auto_delete" eval="True"/>
11 <field name="body_html"><![CDATA[
12 <%page args="object, mode" />
13 %if mode != 'pdf':
14 <!-- your css here -->
15 <style type="text/css">
16 </style>
17 %endif
18 <div>
19
20 <p>Dear ${object.partner_id.name or ''},</p>
21
22 <pre class="custom_text">${object.current_profile_rule.level.custom_text}</pre>
23
24 <table style="border: 1px solid" width="100%">
25 <caption><b>Summary</b></caption>
26 <tr>
27 <th>date due</th>
28 <th>Amount due</th>
29 <th>Amount balance</th>
30 <th>Invoice number</th>
31 </tr>
32%for line in object.credit_lines:
33 <tr>
34 <td>${line.date_due}</td>
35 <td>${line.amount_due}</td>
36 <td>${line.balance_due}</td>
37 %if line.invoice_id:
38 <td>${line.invoice_id.number}</td>
39 %else:
40 <td>n/a</td>
41 %endif
42%endfor
43 </table>
44 <br/>
45 <br/>
46
47 <p> If you have any question, do not hesitate to contact us.</p>
48
49
50 <p>Thank you for choosing ${object.company_id.name}! </p>
51
52 -- more info here --
53 <p>${object.user_id.name} ${object.user_id.user_email and '<%s>'%(object.user_id.user_email) or ''}<br/>
54 ${object.company_id.name}<br/>
55 % if object.company_id.street:
56 ${object.company_id.street or ''}<br/>
57
58 % endif
59
60 % if object.company_id.street2:
61 ${object.company_id.street2}<br/>
62 % endif
63 % if object.company_id.city or object.company_id.zip:
64 ${object.company_id.zip or ''} ${object.company_id.city or ''}<br/>
65 % endif
66 % if object.company_id.country_id:
67 ${object.company_id.state_id and ('%s, ' % object.company_id.state_id.name) or ''} ${object.company_id.country_id.name or ''}<br/>
68 % endif
69 % if object.company_id.phone:
70 Phone: ${object.company_id.phone}<br/>
71 % endif
72 % if object.company_id.website:
73 ${object.company_id.website or ''}<br/>
74 % endif
75 ]]></field>
76 </record>
77
78 <!-- profile no follow -->
79 <record model="credit.management.profile"
80 id="credit_management_no_follow">
81 <field name="name">No follow</field>
82 <field name="do_nothing" eval="1"/>
83 </record>
84
85 <!-- profile 1 -->
86 <record model="credit.management.profile"
87 id="credit_management_3_time">
88 <field name="name">3 time policy</field>
89 </record>
90
91 <record model="credit.management.profile.rule"
92 id="3_time_1">
93 <field name="name">10 days net</field>
94 <field name="level" eval="1"/>
95 <field name="computation_mode">net_days</field>
96 <field name="delay_days" eval="10"/>
97 <field name="mail_template_id" ref="email_template_credit_management_base"/>
98 <field name="profile_id" ref="credit_management_3_time"/>
99 <field name="canal">mail</field>
100 <field name="custom_text">Replace this text in rule by your message</field>
101 </record>
102
103 <record model="credit.management.profile.rule"
104 id="3_time_2">
105 <field name="name">30 days end of month</field>
106 <field name="level" eval="2"/>
107 <field name="computation_mode">end_of_month</field>
108 <field name="delay_days" eval="30"/>
109 <field name="mail_template_id" ref="email_template_credit_management_base"/>
110 <field name="profile_id" ref="credit_management_3_time"/>
111 <field name="canal">mail</field>
112 <field name="custom_text">Replace this text in rule by your message</field>
113 </record>
114
115 <record model="credit.management.profile.rule"
116 id="3_time_3">
117 <field name="name">10 days sommation</field>
118 <field name="level" eval="3"/>
119 <field name="computation_mode">previous_date</field>
120 <field name="delay_days" eval="10"/>
121 <field name="mail_template_id" ref="email_template_credit_management_base"/>
122 <field name="profile_id" ref="credit_management_3_time"/>
123 <field name="canal">manual</field>
124 <field name="custom_text">Replace this text in rule by your message</field>
125 </record>
126
127 <!-- profile 2 -->
128 <record model="credit.management.profile"
129 id="credit_management_2_time">
130 <field name="name">2 time policy</field>
131 </record>
132
133 <record model="credit.management.profile.rule"
134 id="2_time_1">
135 <field name="name">30 days end of month</field>
136 <field name="level" eval="1"/>
137 <field name="computation_mode">end_of_month</field>
138 <field name="delay_days" eval="30"/>
139 <field name="mail_template_id" ref="email_template_credit_management_base"/>
140 <field name="profile_id" ref="credit_management_2_time"/>
141 <field name="canal">mail</field>
142 <field name="custom_text">Replace this text in rule by your message</field>
143 </record>
144
145 <record model="credit.management.profile.rule"
146 id="2_time_2">
147 <field name="name">60 days sommation</field>
148 <field name="level" eval="2"/>
149 <field name="computation_mode">previous_date</field>
150 <field name="delay_days" eval="60"/>
151 <field name="mail_template_id" ref="email_template_credit_management_base"/>
152 <field name="profile_id" ref="credit_management_2_time"/>
153 <field name="canal">manual</field>
154 <field name="custom_text">Replace this text in rule by your message</field>
155 </record>
156
157 <record id="group_account_credit_management_manager" model="res.groups">
158 <field name="name">Credit Management manager</field>
159 <field name="category_id" ref="base.module_category_accounting_and_finance"/>
160 </record>
161
162 <record id="group_account_credit_management_user" model="res.groups" context="{'noadmin':True}">
163 <field name="name">Credit Management user</field>
164 <field name="category_id" ref="base.module_category_accounting_and_finance"/>
165 </record>
166
167 <record id="group_account_credit_management_info" model="res.groups" context="{'noadmin':True}">
168 <field name="name">Credit Management info</field>
169 <field name="category_id" ref="base.module_category_accounting_and_finance"/>
170 </record>
171
172 </data>
173</openerp>
0174
=== added directory 'account_credit_management/i18n'
=== added directory 'account_credit_management/report'
=== added file 'account_credit_management/report/__init__.py'
--- account_credit_management/report/__init__.py 1970-01-01 00:00:00 +0000
+++ account_credit_management/report/__init__.py 2012-10-15 10:14:35 +0000
@@ -0,0 +1,1 @@
1from . import credit_management_summary
02
=== added file 'account_credit_management/report/credit_management_summary.html.mako'
--- account_credit_management/report/credit_management_summary.html.mako 1970-01-01 00:00:00 +0000
+++ account_credit_management/report/credit_management_summary.html.mako 2012-10-15 10:14:35 +0000
@@ -0,0 +1,19 @@
1<html>
2<head>
3 <style type="text/css">
4 ${css}
5 </style>
6</head>
7<body>
8 %for comm in objects :
9 ${setLang(comm.partner_id.lang)}
10 <%
11 current_uri = '%s_profile_template' % (comm.partner_id.lang)
12 if not context.lookup.has_template(current_uri):
13 context.lookup.put_string(current_uri, comm.current_profile_rule.mail_template_id.body_html)
14 %>
15 <%include file="${current_uri}" args="object=comm,mode='pdf'"/>
16 </br>
17 %endfor
18</body>
19</html>
020
=== added file 'account_credit_management/report/credit_management_summary.py'
--- account_credit_management/report/credit_management_summary.py 1970-01-01 00:00:00 +0000
+++ account_credit_management/report/credit_management_summary.py 2012-10-15 10:14:35 +0000
@@ -0,0 +1,37 @@
1# -*- coding: utf-8 -*-
2##############################################################################
3#
4# Author: Nicolas Bessi
5# Copyright 2012 Camptocamp SA
6#
7# This program is free software: you can redistribute it and/or modify
8# it under the terms of the GNU Affero General Public License as
9# published by the Free Software Foundation, either version 3 of the
10# License, or (at your option) any later version.
11#
12# This program is distributed in the hope that it will be useful,
13# but WITHOUT ANY WARRANTY; without even the implied warranty of
14# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15# GNU Affero General Public License for more details.
16#
17# You should have received a copy of the GNU Affero General Public License
18# along with this program. If not, see <http://www.gnu.org/licenses/>.
19#
20##############################################################################
21import time
22
23from openerp.report import report_sxw
24
25class CreditSummaryReport(report_sxw.rml_parse):
26 def __init__(self, cr, uid, name, context):
27 super(CreditSummaryReport, self).__init__(cr, uid, name, context=context)
28 self.localcontext.update({
29 'time': time,
30 'cr':cr,
31 'uid': uid,
32 })
33
34report_sxw.report_sxw('report.credit_management_summary',
35 'credit.management.communication',
36 'addons/account_credit_management/report/credit_management_summary.html.mako',
37 parser=CreditSummaryReport)
038
=== added file 'account_credit_management/report/report.xml'
--- account_credit_management/report/report.xml 1970-01-01 00:00:00 +0000
+++ account_credit_management/report/report.xml 2012-10-15 10:14:35 +0000
@@ -0,0 +1,12 @@
1<openerp>
2 <data>
3 <report auto="False"
4 id="report_webkit_html"
5 model="credit.management.communication"
6 name="credit_management_summary"
7 file="account_credit_management/report/credit_management_summary.html.mako"
8 string="Credit Summary"
9 report_type="webkit"
10 webkit_header="report_webkit.ir_header_webkit_basesample0"/>
11 </data>
12</openerp>
013
=== added directory 'account_credit_management/scenarios'
=== added directory 'account_credit_management/scenarios/credit_management'
=== added file 'account_credit_management/scenarios/credit_management/00_credit_management_param.feature'
--- account_credit_management/scenarios/credit_management/00_credit_management_param.feature 1970-01-01 00:00:00 +0000
+++ account_credit_management/scenarios/credit_management/00_credit_management_param.feature 2012-10-15 10:14:35 +0000
@@ -0,0 +1,23 @@
1###############################################################################
2#
3# OERPScenario, OpenERP Functional Tests
4# Copyright 2009 Camptocamp SA
5#
6##############################################################################
7##############################################################################
8# Branch # Module # Processes # System
9@credit_management_module @credit_management_param
10
11Feature: In order to validate account voucher behavious as an admin user I prepare data
12 @credit_management_addon_install
13 Scenario: Install module
14 Given I need a "ir.module.module" with name: account_voucher
15 And having:
16 |name | value |
17 | demo | 0 |
18
19 Given I do not want all demo data to be loaded on install
20 And I install the required modules with dependencies:
21 | name |
22 | account_credit_management |
23 Then my modules should have been installed and models reloaded
0\ No newline at end of file24\ No newline at end of file
125
=== added file 'account_credit_management/scenarios/credit_management/01_credit_management_partners.feature'
--- account_credit_management/scenarios/credit_management/01_credit_management_partners.feature 1970-01-01 00:00:00 +0000
+++ account_credit_management/scenarios/credit_management/01_credit_management_partners.feature 2012-10-15 10:14:35 +0000
@@ -0,0 +1,60 @@
1###############################################################################
2#
3# OERPScenario, OpenERP Functional Tests
4# Copyright 2009 Camptocamp SA
5#
6##############################################################################
7##############################################################################
8# Branch # Module # Processes # System
9@credit_management_module @credit_management_partner
10
11Feature: I add profile to partners already created
12 @credit_management_partner_1
13 Scenario: Partner_1
14 Given I need a "res.partner" with oid: scen.partner_1
15 And having:
16 | name | value |
17 | name | partner_1 |
18 | credit_profile_id | by name: No follow |
19
20 @credit_management_customer_1
21 Scenario: Customer_1
22 Given I need a "res.partner" with oid: scen.customer_1
23 And having:
24 | name | value |
25 | name | customer_1 |
26 | credit_profile_id | by name: 2 time policy|
27
28 @credit_management_customer_2
29 Scenario: Customer_2
30 Given I need a "res.partner" with oid: scen.customer_2
31 And having:
32 | name | value |
33 | name | customer_2 |
34 | credit_profile_id | by name: 2 time policy|
35
36 @credit_management_customer_3
37 Scenario: Customer_3
38 Given I need a "res.partner" with oid: scen.customer_3
39 And having:
40 | name | value |
41 | name | customer_3 |
42 | credit_profile_id | by name: 2 time policy|
43
44 @credit_management_customer_4
45 Scenario: Customer_4
46 Given I need a "res.partner" with oid: scen.customer_4
47 And having:
48 | name | value |
49 | name | customer_4 |
50 | credit_profile_id | by name: 3 time policy|
51
52 @credit_management_customer_5
53 Scenario: Customer_5
54 Given I need a "res.partner" with oid: scen.customer_5
55 And having:
56 | name | value |
57 | name | customer_5_usd |
58 | credit_profile_id | by name: 3 time policy|
59
60
061
=== added file 'account_credit_management/scenarios/credit_management/credit_management_01_data.feature'
--- account_credit_management/scenarios/credit_management/credit_management_01_data.feature 1970-01-01 00:00:00 +0000
+++ account_credit_management/scenarios/credit_management/credit_management_01_data.feature 2012-10-15 10:14:35 +0000
@@ -0,0 +1,224 @@
1###############################################################################
2#
3# OERPScenario, OpenERP Functional Tests
4# Copyright 2012 Camptocamp SA
5# Author Nicolas Bessi
6##############################################################################
7
8# Features Generic tags (none for all)
9##############################################################################
10
11@credit_management_module @credit_management_base_data
12
13Feature: Ensure that mail credit management is correct
14
15
16 @credit_management_data
17 Scenario: Create data
18 Given I need a "ir.module.module" with name: account_credit_management
19 And having:
20 |name|value|
21 | demo | 1 |
22 Given I install the required modules with dependencies:
23 | name |
24 | account_credit_management |
25 Given I need a "res.partner" with oid: credit_management.trusted_partner
26 And having:
27 | name | value |
28 | name | Credit m. trusted partner |
29 | customer | 1 |
30 | credit_profile_id | by name: No follow |
31
32 Given I need a "res.partner.address" with oid: credit_management.trusted_address
33 And having:
34 | name | value |
35 | name | Luc Maurer |
36 | zip | 1015 |
37 | city | lausanne |
38 | email | openerp@locahost.dummy |
39 | phone | +41 21 619 10 12 |
40 | street | PSE-A, EPF |
41 | partner_id | by oid: credit_management.trusted_partner |
42
43
44 Given I need a "res.partner" with oid: credit_management.not_so_trusted_partner
45 And having:
46 | name | value |
47 | name | Credit m. not so trusted partner |
48 | customer | 1 |
49 | credit_profile_id | by name: 2 time policy |
50
51 Given I need a "res.partner.address" with oid: credit_management.not_so_trusted_address
52 And having:
53 | name | value |
54 | name | Not so trusted |
55 | zip | 1015 |
56 | city | lausanne |
57 | email | openerp@locahost.dummy |
58 | phone | +41 21 619 10 12 |
59 | street | PSE-A, EPF |
60 | partner_id | by oid: credit_management.not_so_trusted_partner |
61
62
63 Given I need a "res.partner" with oid: credit_management.untrusted_partner
64 And having:
65 | name | value |
66 | name | Credit m. untrusted partner |
67 | customer | 1 |
68 | credit_profile_id | by name: 3 time policy |
69
70 Given I need a "res.partner.address" with oid: credit_management.untrusted_address
71 And having:
72 | name | value |
73 | name | Untrusted |
74 | zip | 1015 |
75 | city | lausanne |
76 | email | openerp@locahost.dummy |
77 | phone | +41 21 619 10 12 |
78 | street | PSE-A, EPF |
79 | partner_id | by oid: credit_management.untrusted_partner |
80
81
82 Given I need a "res.partner" with oid: credit_management.lambda_partner
83 And having:
84 | name | value |
85 | name | Credit m. lambda partner |
86 | customer | 1 |
87
88 Given I need a "res.partner.address" with oid: credit_management.lambda_address
89 And having:
90 | name | value |
91 | name | Lambda |
92 | zip | 1015 |
93 | city | lausanne |
94 | email | openerp@locahost.dummy |
95 | phone | +41 21 619 10 12 |
96 | street | PSE-A, EPF |
97 | partner_id | by oid: credit_management.lambda_partner |
98
99
100
101 @inv1
102 Scenario: invoices
103 # trusted invoice on trusted partner no follow
104 Given I need a "account.invoice" with oid: credit_management.inv1
105 And having:
106 | name | value |
107 | name | trusted invoice 1 |
108 | date_invoice | 2012-01-01 |
109 | date_due | 2012-02-15 |
110 | address_invoice_id | by oid: credit_management.trusted_address |
111 | partner_id | by oid: credit_management.trusted_partner |
112 | account_id | by name: Trusted Debtors - (test) |
113 | journal_id | by name: Sales Journal - (test) |
114
115
116 Given I need a "account.invoice.line" with oid: credit_management.inv_line1
117 And having:
118 | name | value |
119 | name | trusted invoice line 1 |
120 | quantity | 1 |
121 | price_unit | 100 |
122 | account_id | by name: Product Sales - (test) |
123 | invoice_id | by oid: credit_management.inv1 |
124 Given I find a "account.invoice" with oid: credit_management.inv1
125 And I open the credit invoice
126
127
128
129 Given I need a "account.invoice" with oid: credit_management.inv2
130 And having:
131 | name | value |
132 | name | lambda invoice 1 |
133 | date_invoice | 2012-01-01 |
134 | date_due | 2012-02-15 |
135 | address_invoice_id | by oid: credit_management.lambda_address |
136 | partner_id | by oid: credit_management.lambda_partner |
137 | account_id | by name: Not so trusted Debtors - (test) |
138 | journal_id | by name: Sales Journal - (test) |
139
140 Given I need a "account.invoice.line" with oid: credit_management.inv_line2
141 And having:
142 | name | value |
143 | name | lambda invoice line 1 |
144 | quantity | 1 |
145 | price_unit | 130 |
146 | account_id | by name: Product Sales - (test) |
147 | invoice_id | by oid: credit_management.inv2 |
148 Given I find a "account.invoice" with oid: credit_management.inv2
149 And I open the credit invoice
150
151
152 Given I need a "account.invoice" with oid: credit_management.inv3
153 And having:
154 | name | value |
155 | name | Not so trusted invoice |
156 | date_invoice | 2012-01-01 |
157 | date_due | 2012-02-15 |
158 | address_invoice_id | by oid: credit_management.not_so_trusted_address |
159 | partner_id | by oid: credit_management.not_so_trusted_partner |
160 | account_id | by name: Not so trusted Debtors - (test) |
161 | journal_id | by name: Sales Journal - (test) |
162
163
164 Given I need a "account.invoice.line" with oid: credit_management.inv_line3
165 And having:
166 | name | value |
167 | name | Not so trusted invoice line 1 |
168 | quantity | 1 |
169 | price_unit | 150 |
170 | account_id | by name: Product Sales - (test) |
171 | invoice_id | by oid: credit_management.inv3 |
172 Given I find a "account.invoice" with oid: credit_management.inv3
173 And I open the credit invoice
174
175
176
177
178 Given I need a "account.invoice" with oid: credit_management.inv4
179 And having:
180 | name | value |
181 | name | Untrusted invoice |
182 | date_invoice | 2012-01-01 |
183 | date_due | 2012-02-15 |
184 | address_invoice_id | by oid: credit_management.untrusted_address |
185 | partner_id | by oid: credit_management.untrusted_partner |
186 | account_id | by name: Not so trusted Debtors - (test) |
187 | journal_id | by name: Sales Journal - (test) |
188
189
190 Given I need a "account.invoice.line" with oid: credit_management.inv_line4
191 And having:
192 | name | value |
193 | name | Un trusted invoice line 1 |
194 | quantity | 1 |
195 | price_unit | 170 |
196 | account_id | by name: Product Sales - (test) |
197 | invoice_id | by oid: credit_management.inv4 |
198 Given I find a "account.invoice" with oid: credit_management.inv4
199 And I open the credit invoice
200
201
202 Given I need a "account.invoice" with oid: credit_management.inv5
203 And having:
204 | name | value |
205 | name | lamba invoice with untrusted policy |
206 | date_invoice | 2012-01-01 |
207 | date_due | 2012-02-15 |
208 | address_invoice_id | by oid: credit_management.lambda_address |
209 | partner_id | by oid: credit_management.lambda_partner |
210 | account_id | by name: Not so trusted Debtors - (test) |
211 | journal_id | by name: Sales Journal - (test) |
212 | credit_profile_id | by name: 3 time policy |
213
214
215 Given I need a "account.invoice.line" with oid: credit_management.inv_line5
216 And having:
217 | name | value |
218 | name | Un trusted invoice line 1 |
219 | quantity | 1 |
220 | price_unit | 200 |
221 | account_id | by name: Product Sales - (test) |
222 | invoice_id | by oid: credit_management.inv5 |
223 Given I find a "account.invoice" with oid: credit_management.inv5
224 And I open the credit invoice
0225
=== added file 'account_credit_management/scenarios/credit_management/credit_management_02_run.feature'
--- account_credit_management/scenarios/credit_management/credit_management_02_run.feature 1970-01-01 00:00:00 +0000
+++ account_credit_management/scenarios/credit_management/credit_management_02_run.feature 2012-10-15 10:14:35 +0000
@@ -0,0 +1,33 @@
1###############################################################################
2#
3# OERPScenario, OpenERP Functional Tests
4# Copyright 2012 Camptocamp SA
5# Author Nicolas Bessi
6##############################################################################
7
8# Features Generic tags (none for all)
9##############################################################################
10
11@credit_management_module
12
13Feature: Ensure that mail credit line generation first pass is correct
14
15
16 @credit_management_first_run
17 Scenario: clean data
18 Given I clean all the credit lines
19 #Given I unreconcile and clean all move line
20
21 @credit_management_first_run
22 Scenario: Create run
23 Given I need a "credit.management.run" with oid: credit_management.run1
24 And having:
25 | name | value |
26 | date | 2012-03-01 |
27 When I launch the credit run
28 Then my credit run should be in state "done"
29 And I should have "2" credit lines of level "1"
30 And credit lines should have following values:
31 | balance | date due | account | profile | date | partner | canal | level | move line | profile rule | state | amount due | currency |
32 | 170 | 2012-02-15 | B2C Debtors - (test) | 3 time policy | 2012-03-01 | Credit m. untrusted partner | mail | 1.00 | Untrusted invoice | 10 days net | draft | 170 | |
33 | 200 | 2012-02-15 | B2C Debtors - (test) | 3 time policy | 2012-03-01 | Credit m. lambda partner | mail | 1.00 | lamba invoice with untrusted policy | 10 days net | draft | 200 | |
034
=== added file 'account_credit_management/scenarios/credit_management/credit_management_03_run.feature'
--- account_credit_management/scenarios/credit_management/credit_management_03_run.feature 1970-01-01 00:00:00 +0000
+++ account_credit_management/scenarios/credit_management/credit_management_03_run.feature 2012-10-15 10:14:35 +0000
@@ -0,0 +1,26 @@
1###############################################################################
2#
3# OERPScenario, OpenERP Functional Tests
4# Copyright 2012 Camptocamp SA
5# Author Nicolas Bessi
6##############################################################################
7
8# Features Generic tags (none for all)
9##############################################################################
10
11@credit_management_mark_mail
12
13Feature: Ensure that mail credit line generation first pass is correct
14
15
16 @credit_management_mark
17 Scenario: mark lines
18 Given there is "draft" credit lines
19 And I mark all draft mail to state "to_be_sent"
20 Then the draft line should be in state "to_be_sent"
21
22 @credit_management_mail
23 Scenario: mail lines
24 Given there is "to_be_sent" credit lines
25 And I mail all ready lines
26 Then All sent lines should be linked to a mail and in mail status "sent"
027
=== added directory 'account_credit_management/scenarios/credit_management/step_definitions'
=== added file 'account_credit_management/scenarios/credit_management/step_definitions/credit_management.rb'
--- account_credit_management/scenarios/credit_management/step_definitions/credit_management.rb 1970-01-01 00:00:00 +0000
+++ account_credit_management/scenarios/credit_management/step_definitions/credit_management.rb 2012-10-15 10:14:35 +0000
@@ -0,0 +1,115 @@
1# Given /^I open the credit invoice$/ do
2# @found_item.should_not be_nil,
3# "no invoice found"
4# ['draft', 'open'].should include(@found_item.state),
5# "Invoice is not draf or open"
6# if @found_item.state == 'draft'
7# @found_item.wkf_action('invoice_open')
8# end
9# end
10
11Then /^I launch the credit run$/ do
12 @found_item.should_not be_nil,
13 "no run found"
14 @found_item.generate_credit_lines()
15end
16
17Given /^there is "(.*?)" credit lines$/ do |state|
18 @credit_lines = CreditManagementLine.find_all_by_state(state)
19 @credit_lines.should_not be_empty,
20 "not #{state} lines found"
21end
22
23Given /^I mark all draft mail to state "(.*?)"$/ do | state |
24 wiz = CreditManagementMarker.new
25 wiz.name = state
26 wiz.mark_all = true
27 wiz.save
28 wiz.mark_lines
29end
30
31Then /^the draft line should be in state "(.*?)"$/ do | state |
32 @credit_lines.should_not be_nil,
33 "no line where stored"
34 @credit_lines.each do |line|
35 line = CreditManagementLine.find(line.id)
36 line.state.should eql(state),
37 "The line #{line.id} is not in state #{state} he is is in state #{line.state} "
38 end
39
40end
41
42Given /^I mail all ready lines$/ do
43 @credit_lines.should_not be_nil,
44 "no line where stored"
45 wiz = CreditManagementMailer.new
46 wiz.mail_all = true
47 wiz.save
48 wiz.mail_lines
49end
50
51Given /^I clean all the credit lines$/ do
52 CreditManagementLine.find(:all).each do | line |
53 line.destroy
54 end
55end
56
57Then /^my credit run should be in state "(.*?)"$/ do |state|
58 @found_item.should_not be nil
59 @run = CreditManagementRun.find(@found_item.id)
60 @run.state.should eq(state),
61 "Run state is in state #{@run.state} instead of #{state}"
62end
63
64
65Then /^All sent lines should be linked to a mail and in mail status "(.*?)"$/ do |status|
66 @credit_lines.should_not be_nil,
67 "no line where stored"
68 @credit_lines.each do |line|
69 line = CreditManagementLine.find(line.id)
70 line.state.should eql(status),
71 "The line #{line.id} is has no mail status #{status} but #{line.state}"
72 end
73end
74
75Then /^I should have "(.*?)" credit lines of level "(.*?)"$/ do |number, level|
76 CreditManagementLine.find_all_by_level(level).length.should eq (number.to_i)
77end
78
79Then /^credit lines should have following values:$/ do |table|
80 h_list = table.hashes
81 h_list.each do | h |
82 h.delete_if {|k, v| v.empty?}
83 end
84 errors = []
85 h_list.each do | row |
86 account = AccountAccount.find_by_name(row['account'], :fields=>['id'])
87 account.should_not be_nil, "no account named #{row['account']} found"
88
89 profile = CreditManagementProfile.find_by_name(row['profile'], :fields=>['id'])
90 profile.should_not be_nil, "No account #{row['account']} found"
91
92 partner = ResPartner.find_by_name(row['partner'], :fields=>['id'])
93 partner.should_not be_nil, "No partner #{row['partner']} found"
94
95 move_line = AccountMoveLine.find_by_name(row['move line'], :fields=>['id'])
96 move_line.should_not be_nil, "No move line #{row['move line']} found"
97
98 rule = CreditManagementProfileRule.find_by_name(row['profile rule'], :fields=>['id'])
99 rule.should_not be_nil, "No profile rune #{row['profile rule']} found"
100
101 domain = [['account_id', '=', account.id], ['profile_id', '=', profile.id],
102 ['partner_id', '=', partner.id], ['move_line_id', '=', move_line.id],
103 ['profile_rule_id', '=', rule.id], ['amount_due', '=', row.fetch('amount due', 0.0)],
104 ['state', '=', row.fetch('state')], ['level', '=', row.fetch('level', 0.0)],
105 ['canal', '=', row.fetch('canal')], ['balance_due', '=', row.fetch('balance', 0.0)],
106 ['date_due', '=', row.fetch('date due')], ['date', '=', row.fetch('date')]]
107 if row['currency']
108 curreny = ResCurrency.find_by_name(row['currency'], :fields=>['id'])
109 domain.push ['currency_id', '=', curreny.id]
110 end
111 pp domain
112 line = CreditManagementLine.find(:first, :domain=>domain)
113 line.should_not be_nil, "Can not find line #{row.inspect}"
114 end
115end
0116
=== added file 'account_credit_management/scenarios/run_command.txt'
--- account_credit_management/scenarios/run_command.txt 1970-01-01 00:00:00 +0000
+++ account_credit_management/scenarios/run_command.txt 2012-10-15 10:14:35 +0000
@@ -0,0 +1,1 @@
1cucumber CONF=nbessi.conf --tags=@credit_management_first_run features /opt/openerp_geoengine/src/c2c-financial-addons/account_credit_management/scenarios/
02
=== added directory 'account_credit_management/security'
=== added file 'account_credit_management/security/ir.model.access.csv'
--- account_credit_management/security/ir.model.access.csv 1970-01-01 00:00:00 +0000
+++ account_credit_management/security/ir.model.access.csv 2012-10-15 10:14:35 +0000
@@ -0,0 +1,27 @@
1"id","perm_create","perm_unlink","group_id/id","name","model_id/id","perm_read","perm_write"
2"account_credit_management.ir_model_access_270",1,1,"group_account_credit_management_manager","credit_management_manager_line","account_credit_management.model_credit_management_line",1,1
3"account_credit_management.ir_model_access_271",1,1,"group_account_credit_management_user","credit_management_user_line","account_credit_management.model_credit_management_line",1,1
4"account_credit_management.ir_model_access_272",0,0,"group_account_credit_management_info","credit_management_info_line","account_credit_management.model_credit_management_line",1,0
5"account_credit_management.ir_model_access_273",1,1,"group_account_credit_management_manager","credit_management_manager_mail_template","email_template.model_email_template",1,1
6"account_credit_management.ir_model_access_274",1,1,"group_account_credit_management_manager","credit_management_manager_mail_template_preview","email_template.model_email_template_preview",1,1
7"account_credit_management.ir_model_access_275",1,1,"group_account_credit_management_manager","credit_management_manager_mail_message","mail.model_mail_message",1,1
8"account_credit_management.ir_model_access_276",1,0,"group_account_credit_management_user","credit_management_user_mail_message","mail.model_mail_message",1,1
9"account_credit_management.ir_model_access_277",0,0,"group_account_credit_management_info","credit_management_info_mail_message","mail.model_mail_message",1,0
10"account_credit_management.ir_model_access_278",1,1,"group_account_credit_management_manager","credit_management_manager_comm","account_credit_management.model_credit_management_communication",1,1
11"account_credit_management.ir_model_access_279",1,1,"base.group_sale_salesman","credit_management_user_comm","account_credit_management.model_credit_management_communication",1,1
12"account_credit_management.ir_model_access_280",0,0,"group_account_credit_management_info","credit_management_info_comm","account_credit_management.model_credit_management_communication",1,0
13"account_credit_management.ir_model_access_281",1,1,"group_account_credit_management_manager","credit_management_mananger_run","account_credit_management.model_credit_management_run",1,1
14"account_credit_management.ir_model_access_282",1,1,"group_account_credit_management_user","credit_management_user_run","account_credit_management.model_credit_management_run",1,1
15"account_credit_management.ir_model_access_283",0,0,"group_account_credit_management_info","credit_management_info_run","account_credit_management.model_credit_management_run",1,0
16"account_credit_management.ir_model_access_284",1,1,"group_account_credit_management_manager","credit_management_manager_profile","account_credit_management.model_credit_management_profile",1,1
17"account_credit_management.ir_model_access_285",0,0,"group_account_credit_management_user","credit_management_user_profile","account_credit_management.model_credit_management_profile",1,0
18"account_credit_management.ir_model_access_286",0,0,"group_account_credit_management_info","credit_management_info_profile","account_credit_management.model_credit_management_profile",1,0
19"account_credit_management.ir_model_access_287",1,1,"group_account_credit_management_manager","credit_management_manager_rule","account_credit_management.model_credit_management_profile_rule",1,1
20"account_credit_management.ir_model_access_288",0,0,"group_account_credit_management_user","credit_management_user_rule","account_credit_management.model_credit_management_profile_rule",1,0
21"account_credit_management.ir_model_access_289",0,0,"group_account_credit_management_info","credit_management_info_rule","account_credit_management.model_credit_management_profile_rule",1,0
22"account_credit_management.ir_model_access_290",1,1,"group_account_credit_management_manager","credit_management_manager_mailer","account_credit_management.model_credit_management_mailer",1,1
23"account_credit_management.ir_model_access_291",1,1,"group_account_credit_management_user","credit_management_user_mailer","account_credit_management.model_credit_management_mailer",1,1
24"account_credit_management.ir_model_access_292",1,1,"group_account_credit_management_manager","credit_management_manager_marker","account_credit_management.model_credit_management_marker",1,1
25"account_credit_management.ir_model_access_293",1,1,"group_account_credit_management_user","credit_management_user_marker","account_credit_management.model_credit_management_marker",1,1
26"account_credit_management.ir_model_access_294",1,1,"group_account_credit_management_manager","credit_management_manager_printer","account_credit_management.model_credit_management_printer",1,1
27"account_credit_management.ir_model_access_295",1,1,"group_account_credit_management_user","credit_management_user_printer","account_credit_management.model_credit_management_printer",1,1
028
=== added directory 'account_credit_management/wizard'
=== added file 'account_credit_management/wizard/__init__.py'
--- account_credit_management/wizard/__init__.py 1970-01-01 00:00:00 +0000
+++ account_credit_management/wizard/__init__.py 2012-10-15 10:14:35 +0000
@@ -0,0 +1,24 @@
1# -*- coding: utf-8 -*-
2##############################################################################
3#
4# Author: Nicolas Bessi
5# Copyright 2012 Camptocamp SA
6#
7# This program is free software: you can redistribute it and/or modify
8# it under the terms of the GNU Affero General Public License as
9# published by the Free Software Foundation, either version 3 of the
10# License, or (at your option) any later version.
11#
12# This program is distributed in the hope that it will be useful,
13# but WITHOUT ANY WARRANTY; without even the implied warranty of
14# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15# GNU Affero General Public License for more details.
16#
17# You should have received a copy of the GNU Affero General Public License
18# along with this program. If not, see <http://www.gnu.org/licenses/>.
19#
20##############################################################################
21from . import credit_management_mailer
22from . import credit_management_marker
23from . import credit_management_printer
24from . import credit_management_communication
025
=== added file 'account_credit_management/wizard/credit_management_communication.py'
--- account_credit_management/wizard/credit_management_communication.py 1970-01-01 00:00:00 +0000
+++ account_credit_management/wizard/credit_management_communication.py 2012-10-15 10:14:35 +0000
@@ -0,0 +1,178 @@
1# -*- coding: utf-8 -*-
2##############################################################################
3#
4# Author: Nicolas Bessi
5# Copyright 2012 Camptocamp SA
6#
7# This program is free software: you can redistribute it and/or modify
8# it under the terms of the GNU Affero General Public License as
9# published by the Free Software Foundation, either version 3 of the
10# License, or (at your option) any later version.
11#
12# This program is distributed in the hope that it will be useful,
13# but WITHOUT ANY WARRANTY; without even the implied warranty of
14# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15# GNU Affero General Public License for more details.
16#
17# You should have received a copy of the GNU Affero General Public License
18# along with this program. If not, see <http://www.gnu.org/licenses/>.
19#
20##############################################################################
21from openerp.osv.orm import TransientModel, fields
22from openerp.osv.osv import except_osv
23from openerp.tools.translate import _
24import netsvc
25import logging
26
27logger = logging.getLogger('credit.line.management mailing')
28
29
30class CreditCommunication(TransientModel):
31 """Shell calss used to provide a base model to email template and reporting.
32 Il use this approche in version 7 a browse record will exist even if not saved"""
33 _name = "credit.management.communication"
34 _description = "credit management communication"
35 _rec_name = 'partner_id'
36 _columns = {'partner_id': fields.many2one('res.partner', 'Partner', required=True),
37
38 'current_profile_rule': fields.many2one('credit.management.profile.rule',
39 'Rule', required=True),
40
41 'credit_lines': fields.many2many('credit.management.line',
42 rel='comm_credit_rel',
43 string='Credit Lines'),
44
45 'company_id': fields.many2one('res.company', 'Company',
46 required=True),
47
48 'user_id': fields.many2one('res.users', 'User')}
49
50 _defaults = {'company_id': lambda s, cr, uid, c: s.pool.get('res.company')._company_default_get(
51 cr, uid, 'credit.management.profile', context=c),
52 'user_id': lambda s, cr, uid, c: uid}
53
54 def get_address(self, cursor, uid, com_id, context=None):
55 """Return a valid address for customer"""
56
57 context = context or {}
58 if isinstance(com_id, list):
59 com_id = com_id[0]
60 current = self.browse(cursor, uid, com_id, context=context)
61 part_obj = self.pool.get('res.partner')
62 adds = part_obj.address_get(cursor, uid, [current.partner_id.id],
63 adr_pref=['invoice', 'default'])
64
65 add = adds.get('invoice', adds.get('default'))
66 if not add:
67 raise except_osv(_('No address for partner %s') % (current.partner_id.name),
68 _('Please set one'))
69 add_obj = self.pool.get('res.partner.address')
70 return add_obj.browse(cursor, uid, add, context=context)
71
72
73 def get_mail(self, cursor, uid, com_id, context=None):
74 """Return a valid email for customer"""
75 context = context or {}
76 if isinstance(com_id, list):
77 com_id = com_id[0]
78 current = self.browse(cursor, uid, com_id, context=context)
79 email = current.get_address().email
80 if not email:
81 raise except_osv(_('No invoicing or default email for partner %s') %
82 (current.partner_id.name),
83 _('Please set one'))
84 return email
85
86 def _get_credit_lines(self, cursor, uid, line_ids, partner_id, rule_id, context=None):
87 """Return credit lines related to a partner and a profile rule"""
88 cr_line_obj = self.pool.get('credit.management.line')
89 cr_l_ids = cr_line_obj.search(cursor,
90 uid,
91 [('id', 'in', line_ids),
92 ('partner_id', '=', partner_id),
93 ('profile_rule_id', '=', rule_id)],
94 context=context)
95 #return cr_line_obj.browse(cursor, uid, cr_l_ids, context=context)
96 return cr_l_ids
97
98 def _generate_comm_from_credit_line_ids(self, cursor, uid, line_ids, context=None):
99 if not line_ids:
100 return []
101 comms = []
102 sql = ("SELECT distinct partner_id, profile_rule_id, credit_management_profile_rule.level"
103 " FROM credit_management_line JOIN credit_management_profile_rule "
104 " ON (credit_management_line.profile_rule_id = credit_management_profile_rule.id)"
105 " WHERE credit_management_line.id in %s"
106 " ORDER by credit_management_profile_rule.level")
107
108 cursor.execute(sql, (tuple(line_ids),))
109 res = cursor.dictfetchall()
110 for rule_assoc in res:
111 data = {}
112 data['credit_lines'] = [(6, 0, self._get_credit_lines(cursor, uid, line_ids,
113 rule_assoc['partner_id'],
114 rule_assoc['profile_rule_id'],
115 context=context))]
116 data['partner_id'] = rule_assoc['partner_id']
117 data['current_profile_rule'] = rule_assoc['profile_rule_id']
118 comm_id = self.create(cursor, uid, data, context=context)
119
120
121 comms.append(self.browse(cursor, uid, comm_id, context=context))
122 return comms
123
124 def _generate_mails(self, cursor, uid, comms, context=None):
125 """Generate mail message using template related to rule"""
126 cr_line_obj = self.pool.get('credit.management.line')
127 mail_temp_obj = self.pool.get('email.template')
128 mail_message_obj = self.pool.get('mail.message')
129 mail_ids = []
130 for comm in comms:
131 # we want to use a local cursor in order to send the maximum
132 # of email
133 try:
134 template = comm.current_profile_rule.mail_template_id.id
135
136 mvalues = mail_temp_obj.generate_email(cursor, uid,
137 template,
138 comm.id,
139 context=context)
140 essential_values = ['subject', 'body_html',
141 'email_from', 'email_to']
142 for val in essential_values:
143 if not mvalues.get(val):
144 raise Exception('Mail generation error with %s', val)
145 mail_id = mail_message_obj.create(cursor, uid, mvalues, context=context)
146
147 cl_ids = [cl.id for cl in comm.credit_lines]
148
149 # we do not use local cusros else we have a lock
150 cr_line_obj.write(cursor, uid, cl_ids,
151 {'mail_message_id': mail_id,
152 'state': 'sent'})
153 mail_ids.append(mail_id)
154 except Exception, exc:
155 logger.error(exc)
156 cursor.rollback()
157 cl_ids = [cl.id for cl in comm.credit_lines]
158 # we do not use local cusros else we have a lock
159 cr_line_obj.write(cursor, uid, cl_ids,
160 {'state': 'mail_error'})
161 finally:
162 cursor.commit()
163 return mail_ids
164
165 def _generate_report(self, cursor, uid, comms, context=None):
166 """Will generate a report by inserting mako template of related profile template"""
167 service = netsvc.LocalService('report.credit_management_summary')
168 ids = [x.id for x in comms]
169 result, format = service.create(cursor, uid, ids, {}, {})
170 return result
171
172 def _mark_credit_line_as_sent(self, cursor, uid, comms, context=None):
173 line_ids = []
174 for comm in comms:
175 line_ids += [x.id for x in comm.credit_lines]
176 l_obj = self.pool.get('credit.management.line')
177 l_obj.write(cursor, uid, line_ids, {'state': 'sent'}, context=context)
178 return line_ids
0179
=== added file 'account_credit_management/wizard/credit_management_mailer.py'
--- account_credit_management/wizard/credit_management_mailer.py 1970-01-01 00:00:00 +0000
+++ account_credit_management/wizard/credit_management_mailer.py 2012-10-15 10:14:35 +0000
@@ -0,0 +1,64 @@
1# -*- coding: utf-8 -*-
2##############################################################################
3#
4# Author: Nicolas Bessi
5# Copyright 2012 Camptocamp SA
6#
7# This program is free software: you can redistribute it and/or modify
8# it under the terms of the GNU Affero General Public License as
9# published by the Free Software Foundation, either version 3 of the
10# License, or (at your option) any later version.
11#
12# This program is distributed in the hope that it will be useful,
13# but WITHOUT ANY WARRANTY; without even the implied warranty of
14# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15# GNU Affero General Public License for more details.
16#
17# You should have received a copy of the GNU Affero General Public License
18# along with this program. If not, see <http://www.gnu.org/licenses/>.
19#
20##############################################################################
21from openerp.osv.orm import TransientModel, fields
22from openerp.osv.osv import except_osv
23from openerp.tools.translate import _
24
25class CreditManagementMailer(TransientModel):
26 """Change the state of lines in mass"""
27
28 _name = "credit.management.mailer"
29 _description = """Mass credit line mailer"""
30 _rec_name = 'id'
31
32 _columns = {'mail_all': fields.boolean('Mail all ready lines')}
33
34
35 def _get_lids(self, cursor, uid, mail_all, active_ids, context=None):
36 """get line to be marked filter done lines"""
37 # TODO DRY with printer
38 line_obj = self.pool.get('credit.management.line')
39 if mail_all:
40 domain = [('state', '=', 'to_be_sent'),
41 ('canal', '=', 'mail')]
42 else:
43 domain = [('state', '=', 'to_be_sent'),
44 ('id', 'in', active_ids),
45 ('canal', '=', 'mail')]
46 return line_obj.search(cursor, uid, domain, context=context)
47
48
49 def mail_lines(self, cursor, uid, wiz_id, context=None):
50 comm_obj = self.pool.get('credit.management.communication')
51 context = context or {}
52 if isinstance(wiz_id, list):
53 wiz_id = wiz_id[0]
54 current = self.browse(cursor, uid, wiz_id, context)
55 lines_ids = context.get('active_ids')
56
57 if not lines_ids and not current.mail_all:
58 raise except_osv(_('Not lines ids are selected'),
59 _('You may check "Mail all ready lines"'))
60 filtered_ids = self._get_lids(cursor, uid, current.mail_all, lines_ids, context)
61 comms = comm_obj._generate_comm_from_credit_line_ids(cursor, uid, filtered_ids,
62 context=context)
63 comm_obj._generate_mails(cursor, uid, comms, context=context)
64 return {}
065
=== added file 'account_credit_management/wizard/credit_management_mailer_view.xml'
--- account_credit_management/wizard/credit_management_mailer_view.xml 1970-01-01 00:00:00 +0000
+++ account_credit_management/wizard/credit_management_mailer_view.xml 2012-10-15 10:14:35 +0000
@@ -0,0 +1,44 @@
1<openerp>
2 <data>
3
4 <record id="credit_line_mailer_form" model="ir.ui.view">
5 <field name="name">credit.line.mailer.form</field>
6 <field name="model">credit.management.mailer</field>
7 <field name="type">form</field>
8 <field name="arch" type="xml">
9 <form> <!-- editable="bottom" -->
10 <separator string="Mail selected lines. Sucessfuly mailed lines will be in state done. Related email will be linked to the line" colspan="4"/>
11 <newline/>
12 <field name="mail_all" colspan="4"/>
13 <newline/>
14 <group colspan="4">
15 <button name="mail_lines" string="Mail lines" type="object" icon="gtk-execute"/>
16 <button special="cancel" string="Cancel" icon='gtk-cancel'/>
17 </group>
18 </form>
19 </field>
20 </record>
21
22 <!-- for menu -->
23 <act_window name="Mail lines"
24 res_model="credit.management.mailer"
25 src_model="credit.management.line"
26 view_mode="form"
27 target="new"
28 key2="client_action_multi"
29 id="open_credit_line_mailer_wizard_menu_action"/>
30
31 <!-- for button -->
32 <record id="open_credit_line_mailer_wizard" model="ir.actions.act_window">
33 <field name="name">Mail lines</field>
34 <field name="res_model">credit.management.mailer</field>
35 <field name="view_type">form</field>
36 <field name="view_mode">form</field>
37 <field name="view_id" ref="credit_line_mailer_form"/>
38 <field name="target">new</field>
39 <field name="help">Mail all marked lines</field>
40 </record>
41
42
43 </data>
44</openerp>
045
=== added file 'account_credit_management/wizard/credit_management_marker.py'
--- account_credit_management/wizard/credit_management_marker.py 1970-01-01 00:00:00 +0000
+++ account_credit_management/wizard/credit_management_marker.py 2012-10-15 10:14:35 +0000
@@ -0,0 +1,83 @@
1# -*- coding: utf-8 -*-
2##############################################################################
3#
4# Author: Nicolas Bessi
5# Copyright 2012 Camptocamp SA
6#
7# This program is free software: you can redistribute it and/or modify
8# it under the terms of the GNU Affero General Public License as
9# published by the Free Software Foundation, either version 3 of the
10# License, or (at your option) any later version.
11#
12# This program is distributed in the hope that it will be useful,
13# but WITHOUT ANY WARRANTY; without even the implied warranty of
14# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15# GNU Affero General Public License for more details.
16#
17# You should have received a copy of the GNU Affero General Public License
18# along with this program. If not, see <http://www.gnu.org/licenses/>.
19#
20##############################################################################
21from openerp.osv.orm import TransientModel, fields
22from openerp.osv.osv import except_osv
23from openerp.tools.translate import _
24
25class CreditManagementMarker(TransientModel):
26 """Change the state of lines in mass"""
27
28 _name = "credit.management.marker"
29 _description = """Mass marker"""
30 _columns = {'name': fields.selection([('to_be_sent', 'To be sent'),
31 ('sent', 'Done')],
32 'Mark as', required=True),
33
34 'mark_all': fields.boolean('Mark all draft lines')}
35
36 _defaults = {'name': 'to_be_sent'}
37
38 def _get_lids(self, cursor, uid, mark_all, active_ids, context=None):
39 """get line to be marked filter done lines"""
40 line_obj = self.pool.get('credit.management.line')
41 if mark_all:
42 domain = [('state', '=', 'draft')]
43 else:
44 domain = [('state', '!=', 'sent'), ('id', 'in', active_ids)]
45 return line_obj.search(cursor, uid, domain, context=context)
46
47 def _mark_lines(self, cursor, uid, filtered_ids, state, context=None):
48 """write hook"""
49 line_obj = self.pool.get('credit.management.line')
50 if not state:
51 raise ValueError(_('state can not be empty'))
52 line_obj.write(cursor, uid, filtered_ids, {'state': state})
53 return filtered_ids
54
55
56
57 def mark_lines(self, cursor, uid, wiz_id, context=None):
58 """Write state of selected credit lines to the one in entry
59 done credit line will be ignored"""
60 context = context or {}
61 if isinstance(wiz_id, list):
62 wiz_id = wiz_id[0]
63 current = self.browse(cursor, uid, wiz_id, context)
64 lines_ids = context.get('active_ids')
65
66 if not lines_ids and not current.mark_all:
67 raise except_osv(_('Not lines ids are selected'),
68 _('You may check "Mark all draft lines"'))
69 filtered_ids = self._get_lids(cursor, uid, current.mark_all, lines_ids, context)
70 if not filtered_ids:
71 raise except_osv(_('No lines will be changed'),
72 _('All selected lines are allready done'))
73
74 # hook function a simple write should be enought
75 self._mark_lines(cursor, uid, filtered_ids, current.name, context)
76
77 return {'domain': "[('id','in',%s)]" % (filtered_ids,),
78 'name': _('%s marked line') % (current.name,),
79 'view_type': 'form',
80 'view_mode': 'tree,form',
81 'view_id': False,
82 'res_model': 'credit.management.line',
83 'type': 'ir.actions.act_window'}
084
=== added file 'account_credit_management/wizard/credit_management_marker_view.xml'
--- account_credit_management/wizard/credit_management_marker_view.xml 1970-01-01 00:00:00 +0000
+++ account_credit_management/wizard/credit_management_marker_view.xml 2012-10-15 10:14:35 +0000
@@ -0,0 +1,44 @@
1<openerp>
2 <data>
3
4 <record id="credit_line_marker_form" model="ir.ui.view">
5 <field name="name">credit.line.marker.form</field>
6 <field name="model">credit.management.marker</field>
7 <field name="type">form</field>
8 <field name="arch" type="xml">
9 <form> <!-- editable="bottom" -->
10 <separator string="This wizard will mark selected draft lines to the selected state. Done Lines will be ignored " colspan="4"/>
11 <newline/>
12 <field name="name"/>
13 <field name="mark_all"/>
14 <newline/>
15 <group colspan="4">
16 <button name="mark_lines" string="Mark lines" type="object" icon="gtk-execute"/>
17 <button special="cancel" string="Cancel" icon='gtk-cancel'/>
18 </group>
19 </form>
20 </field>
21 </record>
22
23 <!-- for menu -->
24 <act_window name="Mark lines"
25 res_model="credit.management.marker"
26 src_model="credit.management.line"
27 view_mode="form"
28 target="new"
29 key2="client_action_multi"
30 id="open_credit_line_marker_wizard_menu_action"/>
31
32 <record id="open_credit_line_marker_wizard" model="ir.actions.act_window">
33 <field name="name">Mark lines</field>
34 <field name="res_model">credit.management.marker</field>
35 <field name="src_model">credit.management.line</field>
36 <field name="view_type">form</field>
37 <field name="view_mode">form</field>
38 <field name="view_id" ref="credit_line_marker_form"/>
39 <field name="target">new</field>
40 <field name="help">Mark all lines. You can the send marked lines</field>
41 </record>
42
43 </data>
44</openerp>
045
=== added file 'account_credit_management/wizard/credit_management_printer.py'
--- account_credit_management/wizard/credit_management_printer.py 1970-01-01 00:00:00 +0000
+++ account_credit_management/wizard/credit_management_printer.py 2012-10-15 10:14:35 +0000
@@ -0,0 +1,74 @@
1# -*- coding: utf-8 -*-
2##############################################################################
3#
4# Author: Nicolas Bessi
5# Copyright 2012 Camptocamp SA
6#
7# This program is free software: you can redistribute it and/or modify
8# it under the terms of the GNU Affero General Public License as
9# published by the Free Software Foundation, either version 3 of the
10# License, or (at your option) any later version.
11#
12# This program is distributed in the hope that it will be useful,
13# but WITHOUT ANY WARRANTY; without even the implied warranty of
14# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15# GNU Affero General Public License for more details.
16#
17# You should have received a copy of the GNU Affero General Public License
18# along with this program. If not, see <http://www.gnu.org/licenses/>.
19#
20##############################################################################
21import base64
22
23from openerp.osv.orm import TransientModel, fields
24from openerp.osv.osv import except_osv
25from openerp.tools.translate import _
26
27class CreditManagementPrinter(TransientModel):
28 """Change the state of lines in mass"""
29
30 _name = "credit.management.printer"
31 _rec_name = 'id'
32 _description = """Mass printer"""
33 _columns = {'mark_as_sent': fields.boolean('Mark lines as send',
34 help="Lines to emailed will be ignored"),
35 'print_all': fields.boolean('Print all ready lines'),
36 'report_file': fields.binary('Generated Report'),
37 'state': fields.char('state', size=32)}
38
39 def _get_lids(self, cursor, uid, print_all, active_ids, context=None):
40 """get line to be marked filter done lines"""
41 # TODO Dry with mailer maybe in comm
42 line_obj = self.pool.get('credit.management.line')
43 if print_all:
44 domain = [('state', '=', 'to_be_sent'),
45 ('canal', '=', 'manual')]
46 else:
47 domain = [('state', '=', 'to_be_sent'),
48 ('id', 'in', active_ids),
49 ('canal', '=', 'manual')]
50 return line_obj.search(cursor, uid, domain, context=context)
51
52
53 def print_lines(self, cursor, uid, wiz_id, context=None):
54 comm_obj = self.pool.get('credit.management.communication')
55 context = context or {}
56 if isinstance(wiz_id, list):
57 wiz_id = wiz_id[0]
58 current = self.browse(cursor, uid, wiz_id, context)
59 lines_ids = context.get('active_ids')
60 if not lines_ids and not current.print_all:
61 raise except_osv(_('Not lines ids are selected'),
62 _('You may check "Print all ready lines"'))
63 if current.print_all:
64 filtered_ids = self._get_lids(cursor, uid, current.print_all, lines_ids, context)
65 else:
66 filtered_ids = lines_ids
67 comms = comm_obj._generate_comm_from_credit_line_ids(cursor, uid, filtered_ids,
68 context=context)
69 report_file = comm_obj._generate_report(cursor, uid, comms, context=context)
70 current.write({'report_file': base64.b64encode(report_file), 'state': 'done'})
71 if current.mark_as_sent:
72 filtered_ids = self._get_lids(cursor, uid, False, lines_ids, context)
73 comm_obj._mark_credit_line_as_sent(cursor, uid, comms, context=context)
74 return False
075
=== added file 'account_credit_management/wizard/credit_management_printer_view.xml'
--- account_credit_management/wizard/credit_management_printer_view.xml 1970-01-01 00:00:00 +0000
+++ account_credit_management/wizard/credit_management_printer_view.xml 2012-10-15 10:14:35 +0000
@@ -0,0 +1,47 @@
1<openerp>
2 <data>
3
4 <record id="credit_line_printer_form" model="ir.ui.view">
5 <field name="name">credit.line.printer.form</field>
6 <field name="model">credit.management.printer</field>
7 <field name="type">form</field>
8 <field name="arch" type="xml">
9 <form> <!-- editable="bottom" -->
10 <separator colspan="4" string="This wizard will print all manual lines. Mark lines, lines will pass lines to state done. Lines with canal email will not be passed to state done"/>
11 <newline/>
12 <field name="mark_as_sent"/>
13 <field name="print_all"/>
14 <newline/>
15 <field name="report_file" attrs="{'readonly': [('state', '!=', 'done')]}" colspan="4"/>
16 <field name="state" invisible="1" />
17 <newline/>
18 <group colspan="4">
19 <button name="print_lines" string="Print lines" type="object" icon="gtk-execute"/>
20 <button special="cancel" string="Cancel" icon='gtk-cancel'/>
21 </group>
22 </form>
23 </field>
24 </record>
25
26 <!-- for menu -->
27 <act_window name="Print lines"
28 res_model="credit.management.printer"
29 src_model="credit.management.line"
30 view_mode="form"
31 target="new"
32 key2="client_action_multi"
33 id="open_credit_line_printer_wizard_menu_action"/>
34
35 <record id="open_credit_line_printer_wizard" model="ir.actions.act_window">
36 <field name="name">Print lines</field>
37 <field name="res_model">credit.management.printer</field>
38 <field name="src_model">credit.management.line</field>
39 <field name="view_type">form</field>
40 <field name="view_mode">form</field>
41 <field name="view_id" ref="credit_line_printer_form"/>
42 <field name="target">new</field>
43 <field name="help">Print all lines</field>
44 </record>
45
46 </data>
47</openerp>
048
=== modified file 'account_fiscal_position_rule_m2m/fiscal_rules.py'
--- account_fiscal_position_rule_m2m/fiscal_rules.py 2012-04-03 14:27:22 +0000
+++ account_fiscal_position_rule_m2m/fiscal_rules.py 2012-10-15 10:14:35 +0000
@@ -177,8 +177,8 @@
177 )177 )
178178
179 for field in account_fiscal_position_rule.m2o_replaced_fields:179 for field in account_fiscal_position_rule.m2o_replaced_fields:
180 field_ids = [item.id for item in template[field]]180 field_ids = [item.id for item in template["%s_ids"%field]]
181 vals[field] = [(6, 0, field_ids)]181 vals["%s_ids"%field] = [(6, 0, field_ids)]
182182
183 return vals183 return vals
184184
185185
=== added directory 'account_payment_ext'
=== added file 'account_payment_ext/__init__.py'
--- account_payment_ext/__init__.py 1970-01-01 00:00:00 +0000
+++ account_payment_ext/__init__.py 2012-10-15 10:14:35 +0000
@@ -0,0 +1,32 @@
1# -*- encoding: utf-8 -*-
2#
3# c2c_scan_bvr
4#
5# Created by Nicolas Bessi and Vincent Renaville
6#
7# Copyright (c) 2012 CamptoCamp. All rights reserved.
8##############################################################################
9#
10# WARNING: This program as such is intended to be used by professional
11# programmers who take the whole responsability of assessing all potential
12# consequences resulting from its eventual inadequacies and bugs
13# End users who are looking for a ready-to-use solution with commercial
14# garantees and support are strongly adviced to contract a Free Software
15# Service Company
16#
17# This program is Free Software; you can redistribute it and/or
18# modify it under the terms of the GNU General Public License
19# as published by the Free Software Foundation; either version 2
20# of the License, or (at your option) any later version.
21#
22# This program is distributed in the hope that it will be useful,
23# but WITHOUT ANY WARRANTY; without even the implied warranty of
24# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
25# GNU General Public License for more details.
26#
27# You should have received a copy of the GNU General Public License
28# along with this program; if not, write to the Free Software
29# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
30#
31##############################################################################
32import account_payment
0\ No newline at end of file33\ No newline at end of file
134
=== added file 'account_payment_ext/__openerp__.py'
--- account_payment_ext/__openerp__.py 1970-01-01 00:00:00 +0000
+++ account_payment_ext/__openerp__.py 2012-10-15 10:14:35 +0000
@@ -0,0 +1,50 @@
1# -*- encoding: utf-8 -*-
2#
3# c2c_scan_bvr
4#
5# Created by Nicolas Bessi and Vincent Renaville
6#
7# Copyright (c) 2012 CamptoCamp. All rights reserved.
8##############################################################################
9#
10# WARNING: This program as such is intended to be used by professional
11# programmers who take the whole responsability of assessing all potential
12# consequences resulting from its eventual inadequacies and bugs
13# End users who are looking for a ready-to-use solution with commercial
14# garantees and support are strongly adviced to contract a Free Software
15# Service Company
16#
17# This program is Free Software; you can redistribute it and/or
18# modify it under the terms of the GNU General Public License
19# as published by the Free Software Foundation; either version 2
20# of the License, or (at your option) any later version.
21#
22# This program is distributed in the hope that it will be useful,
23# but WITHOUT ANY WARRANTY; without even the implied warranty of
24# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
25# GNU General Public License for more details.
26#
27# You should have received a copy of the GNU General Public License
28# along with this program; if not, write to the Free Software
29# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
30#
31##############################################################################
32{
33 "name" : "Account Payment improvement",
34 "description" : """In case of a payment order
35 set to pay directly , when the payment will pass to stade done, it will set payment line date to the current date
36 """,
37 "version" : "1.0",
38 "author" : "Camptocamp",
39 "category" : "Generic Modules/Others",
40 "website": "http://www.camptocamp.com",
41 "depends" : [
42 "account_payment"
43 ],
44 "init_xml" : [],
45 "update_xml" : [
46 'account_payment_view.xml'
47 ],
48 "active": False,
49 "installable": True
50}
051
=== added file 'account_payment_ext/account_payment.py'
--- account_payment_ext/account_payment.py 1970-01-01 00:00:00 +0000
+++ account_payment_ext/account_payment.py 2012-10-15 10:14:35 +0000
@@ -0,0 +1,47 @@
1# -*- coding: utf-8 -*-
2##############################################################################
3#
4# OpenERP, Open Source Management Solution
5# Copyright (C) 2004-2010 Tiny SPRL (<http://tiny.be>).
6#
7# This program is free software: you can redistribute it and/or modify
8# it under the terms of the GNU Affero General Public License as
9# published by the Free Software Foundation, either version 3 of the
10# License, or (at your option) any later version.
11#
12# This program is distributed in the hope that it will be useful,
13# but WITHOUT ANY WARRANTY; without even the implied warranty of
14# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15# GNU Affero General Public License for more details.
16#
17# You should have received a copy of the GNU Affero General Public License
18# along with this program. If not, see <http://www.gnu.org/licenses/>.
19#
20##############################################################################
21
22import time
23
24from osv import osv, fields
25import netsvc
26
27
28class payment_order(osv.osv):
29 _inherit = 'payment.order'
30 ### It will set the date
31 def action_open(self, cr, uid, ids, *args):
32 return_code = super(payment_order,self).action_open(cr, uid, ids, args)
33 payment_line_obj = self.pool.get('payment.line')
34 if return_code:
35 for order in self.browse(cr,uid,ids):
36 ### In the case of a date prefered to Directy , we set the current date into the bank statement
37 if order.date_prefered == 'now':
38 for line in order.line_ids:
39 ## in case of no date defined on line
40 if not line.date:
41 payment_line_obj.write(cr, uid, [line.id], {'date': time.strftime('%Y-%m-%d')})
42 return return_code
43
44payment_order()
45
46
47# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
048
=== added file 'account_payment_ext/account_payment_view.xml'
--- account_payment_ext/account_payment_view.xml 1970-01-01 00:00:00 +0000
+++ account_payment_ext/account_payment_view.xml 2012-10-15 10:14:35 +0000
@@ -0,0 +1,18 @@
1<?xml version="1.0" encoding="utf-8"?>
2<openerp>
3 <data>
4
5 <record id="view_payment_order_form_date_required" model="ir.ui.view">
6 <field name="name">payment.order.form</field>
7 <field name="model">payment.order</field>
8 <field name="inherit_id" ref="account_payment.view_payment_order_form"/>
9 <field name="type">form</field>
10 <field name="arch" type="xml">
11 <xpath expr='//field[@name="date_scheduled"]' position='replace'>
12 <field name="date_scheduled" select="1" attrs="{'readonly':[('date_prefered','!=','fixed')],'required':[('date_prefered','=','fixed')]}" />
13 </xpath>
14 </field>
15 </record>
16
17 </data>
18</openerp>
019
=== added directory 'account_payment_ext/i18n'

Subscribers

People subscribed via source and target branches