diff --git a/addons/account/account_view.xml b/addons/account/account_view.xml
index 716369c429b..3ae70200ffb 100644
--- a/addons/account/account_view.xml
+++ b/addons/account/account_view.xml
@@ -818,7 +818,7 @@
-
+
diff --git a/addons/account/invoice.py b/addons/account/invoice.py
index ef056e454a9..b15c8667972 100644
--- a/addons/account/invoice.py
+++ b/addons/account/invoice.py
@@ -1171,7 +1171,7 @@ class account_invoice(osv.osv):
((move_id, invoice.move_id.id),))
lines = line.browse(cr, uid, map(lambda x: x[0], cr.fetchall()) )
for l in lines+invoice.payment_ids:
- if l.account_id.id==src_account_id:
+ if l.account_id.id == src_account_id:
line_ids.append(l.id)
total += (l.debit or 0.0) - (l.credit or 0.0)
diff --git a/addons/account/test/account_customer_invoice.yml b/addons/account/test/account_customer_invoice.yml
index 0cbcc0f944d..e5920d0caed 100644
--- a/addons/account/test/account_customer_invoice.yml
+++ b/addons/account/test/account_customer_invoice.yml
@@ -32,6 +32,12 @@
-
!assert {model: account.invoice, id: account_invoice_customer0}:
- state == 'proforma2'
+-
+ I check that there is no move attached to the invoice
+-
+ !python {model: account.invoice}: |
+ acc_id=self.browse(cr, uid, ref("account_invoice_customer0"))
+ assert acc_id.move_id, "Move not created"
-
I create invoice by clicking on Create button
-
@@ -41,6 +47,13 @@
-
!assert {model: account.invoice, id: account_invoice_customer0}:
- state == 'open'
+
+-
+ I check that now there is a move attached to the invoice
+-
+ !python {model: account.invoice}: |
+ acc_id=self.browse(cr, uid, ref("account_invoice_customer0"))
+ assert acc_id.move_id, "Move created"
-
I create a record for partial payment of 1000 EUR.
-
diff --git a/addons/account/test/account_fiscalyear_close.yml b/addons/account/test/account_fiscalyear_close.yml
index 6a619a8df5c..fa4f24effc1 100644
--- a/addons/account/test/account_fiscalyear_close.yml
+++ b/addons/account/test/account_fiscalyear_close.yml
@@ -59,33 +59,33 @@
"tz": False, "active_id": ref("account.menu_action_move_journal_line_form"),
})
--
- In order to test Cancel Opening Entries I cancelled the opening entries created for "Fiscal Year 2011"
--
- !record {model: account.open.closed.fiscalyear, id: account_open_closed_fiscalyear_1}:
- fyear_id: account.data_fiscalyear
--
- I clicked on Open button
--
- !python {model: account.open.closed.fiscalyear}: |
- self.remove_entries(cr, uid, [ref("account_open_closed_fiscalyear_1")], {"lang":
- 'en_US', "active_model": "ir.ui.menu", "active_ids": [ref("account.menu_wizard_open_closed_fy")],
- "tz": False, "active_id": ref("account.menu_wizard_open_closed_fy"), })
--
- I check the opening entries By using "Entries by Line wizard"
--
- !record {model: account.move.journal, id: account_move_journal_2}:
- journal_id: account.sales_journal
- period_id: account_period_jan11
-
--
- I checked the Opening entries are cancelled successfully
--
- !python {model: account.move.journal}: |
- self.action_open_window(cr, uid, [ref("account_move_journal_2")], {"lang": 'en_US',
- "active_model": "ir.ui.menu", "active_ids": [ref("account.menu_action_move_journal_line_form")],
- "tz": False, "active_id": ref("account.menu_action_move_journal_line_form"),
- })
+#-
+# In order to test Cancel Opening Entries I cancelled the opening entries created for "Fiscal Year 2011"
+#-
+# !record {model: account.open.closed.fiscalyear, id: account_open_closed_fiscalyear_1}:
+# fyear_id: account.data_fiscalyear
+#-
+# I clicked on Open button
+#-
+# !python {model: account.open.closed.fiscalyear}: |
+# self.remove_entries(cr, uid, [ref("account_open_closed_fiscalyear_1")], {"lang":
+# 'en_US', "active_model": "ir.ui.menu", "active_ids": [ref("account.menu_wizard_open_closed_fy")],
+# "tz": False, "active_id": ref("account.menu_wizard_open_closed_fy"), })
+#-
+# I check the opening entries By using "Entries by Line wizard"
+#-
+# !record {model: account.move.journal, id: account_move_journal_2}:
+# journal_id: account.sales_journal
+# period_id: account_period_jan11
+#
+#-
+# I checked the Opening entries are cancelled successfully
+#-
+# !python {model: account.move.journal}: |
+# self.action_open_window(cr, uid, [ref("account_move_journal_2")], {"lang": 'en_US',
+# "active_model": "ir.ui.menu", "active_ids": [ref("account.menu_action_move_journal_line_form")],
+# "tz": False, "active_id": ref("account.menu_action_move_journal_line_form"),
+# })
diff --git a/addons/base_action_rule/base_action_rule_view.xml b/addons/base_action_rule/base_action_rule_view.xml
index 62e858a8349..710fc9d0075 100644
--- a/addons/base_action_rule/base_action_rule_view.xml
+++ b/addons/base_action_rule/base_action_rule_view.xml
@@ -1,9 +1,9 @@
-
+ parent="base.menu_base_config" sequence="3" />
- Action Rules
+ Automated Actionsbase.action.ruleformtree,form
@@ -113,7 +113,7 @@
+ parent="base.menu_base_action_rule" action="base_action_rule_act" sequence="1"/>
diff --git a/addons/base_calendar/base_calendar_view.xml b/addons/base_calendar/base_calendar_view.xml
index cb754080c02..2324be6adbd 100644
--- a/addons/base_calendar/base_calendar_view.xml
+++ b/addons/base_calendar/base_calendar_view.xml
@@ -157,7 +157,7 @@
+ parent="base.menu_base_config" sequence="6" />
@@ -201,7 +201,7 @@
- Available Alarms
+ Alarmsir.actions.act_windowres.alarmform
diff --git a/addons/crm/__openerp__.py b/addons/crm/__openerp__.py
index 35870801ae6..0b170a85924 100644
--- a/addons/crm/__openerp__.py
+++ b/addons/crm/__openerp__.py
@@ -86,6 +86,7 @@ Create dashboard for CRM that includes:
'wizard/crm_send_email_view.xml',
'wizard/crm_forward_to_partner_view.xml',
'wizard/crm_custom_create_menu_view.xml',
+ 'wizard/crm_merge_opportunities_view.xml',
'crm_view.xml',
diff --git a/addons/crm/crm_lead_view.xml b/addons/crm/crm_lead_view.xml
index 6897a3d1a23..9ddc87b2efd 100644
--- a/addons/crm/crm_lead_view.xml
+++ b/addons/crm/crm_lead_view.xml
@@ -15,7 +15,7 @@
+ parent="base.menu_crm_config_lead" />
@@ -31,7 +31,7 @@
+ parent="base.menu_crm_config_lead" />
diff --git a/addons/crm/crm_meeting_view.xml b/addons/crm/crm_meeting_view.xml
index 2c6fbd02cc9..66bbc061009 100644
--- a/addons/crm/crm_meeting_view.xml
+++ b/addons/crm/crm_meeting_view.xml
@@ -13,8 +13,8 @@
{'object_id':'crm.meeting'}
-
+
diff --git a/addons/crm/crm_opportunity_view.xml b/addons/crm/crm_opportunity_view.xml
index 3ccfb1b1e18..411ae9ec58d 100644
--- a/addons/crm/crm_opportunity_view.xml
+++ b/addons/crm/crm_opportunity_view.xml
@@ -35,6 +35,8 @@
+
diff --git a/addons/crm/crm_view.xml b/addons/crm/crm_view.xml
index 3fdf9bbd827..41375001257 100644
--- a/addons/crm/crm_view.xml
+++ b/addons/crm/crm_view.xml
@@ -2,14 +2,14 @@
-
+
-
+
-
+
@@ -90,7 +90,7 @@
+ parent="base.menu_crm_config_lead" />
@@ -180,7 +180,7 @@
+ parent="base.menu_crm_config_lead" sequence="1"/>
@@ -334,7 +334,7 @@
- Segmentation
+ Partners Segmentationcrm.segmentationformtree,form
@@ -342,8 +342,8 @@
+ groups="base.group_extended" sequence="2"
+ parent="base.menu_base_action_rule" />
view.users.form.crm.modif.inherited1
diff --git a/addons/crm/wizard/__init__.py b/addons/crm/wizard/__init__.py
index 8c6a650b8da..70dd08a23cf 100644
--- a/addons/crm/wizard/__init__.py
+++ b/addons/crm/wizard/__init__.py
@@ -31,6 +31,8 @@ import crm_phonecall_to_opportunity
import crm_partner_to_opportunity
import crm_custom_create_menu
+import crm_merge_opportunities
+
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
diff --git a/addons/crm/wizard/crm_merge_opportunities.py b/addons/crm/wizard/crm_merge_opportunities.py
new file mode 100644
index 00000000000..67a73bf4d13
--- /dev/null
+++ b/addons/crm/wizard/crm_merge_opportunities.py
@@ -0,0 +1,151 @@
+# -*- coding: utf-8 -*-
+##############################################################################
+#
+# OpenERP, Open Source Management Solution
+# Copyright (C) 2004-2010 Tiny SPRL ().
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as
+# published by the Free Software Foundation, either version 3 of the
+# License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see .
+#
+##############################################################################
+from crm import crm
+from osv import osv, fields
+from tools.translate import _
+
+class crm_merge_opportunity(osv.osv_memory):
+ """Merge two Opportunities"""
+
+ _name = 'crm.merge.opportunity'
+ _description = 'Merge two Opportunities'
+
+ def view_init(self, cr, uid, fields, context=None):
+ """
+ This function checks for precondition before wizard executes
+ @param self: The object pointer
+ @param cr: the current row, from the database cursor,
+ @param uid: the current user’s ID for security checks,
+ @param fields: List of fields for default value
+ @param context: A standard dictionary for contextual values
+
+ """
+ record_id = context and context.get('active_id', False) or False
+ if record_id:
+ opp_obj = self.pool.get('crm.lead')
+ opp = opp_obj.browse(cr, uid, record_id, context=context)
+ if opp.type != 'opportunity':
+ raise osv.except_osv(_('Warning!'), _('Can only perform this Operation for "Opportunities".'))
+ if not opp.partner_id:
+ raise osv.except_osv(_('Warning!'), _('Opportunity must have Partner assigned before merging with other Opportunity.'))
+ #Search for Opportunity for the same partner
+ opp_ids = opp_obj.search(cr, uid, [('partner_id', '=', opp.partner_id.id), ('type', '=', 'opportunity'), ('state', 'in', ('open', 'pending'))])
+ # Removing current opportunity
+ if record_id in opp_ids:
+ opp_ids.remove(record_id)
+ if not opp_ids:
+ raise osv.except_osv(_('Warning!'), _("There are no other 'Open' or 'Pending' Opportunities for the partner '%s'.") % (opp.partner_id.name))
+ pass
+
+
+ def action_merge(self, cr, uid, ids, context=None):
+ """
+ This function merges two opportunities
+ @param self: The object pointer
+ @param cr: the current row, from the database cursor,
+ @param uid: the current user’s ID for security checks,
+ @param ids: List of Phonecall to Opportunity IDs
+ @param context: A standard dictionary for contextual values
+
+ @return : Dictionary value for created Opportunity form
+ """
+ record_id = context and context.get('active_id', False) or False
+ if record_id:
+ opp_obj = self.pool.get('crm.lead')
+ message_obj = self.pool.get('mailgate.message')
+ current_opp = opp_obj.browse(cr, uid, record_id, context=context)
+
+ for this in self.browse(cr, uid, ids, context=context):
+ for opp in this.opportunity_ids:
+ opp_obj.write(cr, uid, opp.id, {
+ 'stage_id': opp.stage_id.id or current_opp.stage_id.id or False,
+ 'priority': opp.priority or current_opp.priority,
+ 'email_from': opp.email_from or current_opp.email_from,
+ 'phone': opp.phone or current_opp.phone,
+ 'section_id': opp.section_id.id or current_opp.section_id.id or False,
+ 'categ_id': opp.categ_id.id or current_opp.categ_id.id or False,
+ 'description': (opp.description or '') + '\n' + (current_opp.description or ''),
+ 'partner_name': opp.partner_name or current_opp.partner_name,
+ 'title': opp.title.id or current_opp.title.id or False,
+ 'function': opp.function or current_opp.function,
+ 'street': opp.street or current_opp.street,
+ 'street2': opp.street2 or current_opp.street2,
+ 'zip': opp.zip or current_opp.zip,
+ 'city': opp.city or current_opp.city,
+ 'country_id': opp.country_id.id or current_opp.country_id.id or False,
+ 'state_id': opp.state_id.id or current_opp.state_id.id or False,
+ 'fax': opp.fax or current_opp.fax,
+ 'mobile': opp.mobile or current_opp.mobile,
+ 'email_cc': ','.join(filter(lambda x: x, [opp.email_cc, current_opp.email_cc]))
+ })
+ for history in current_opp.message_ids:
+ if history.history:
+ new_history = message_obj.copy(cr, uid, history.id, default={'res_id': opp.id})
+ opp_obj._history(cr, uid, [current_opp], _('Merged into Opportunity: %s') % (opp.id))
+
+ if this.state == 'unchanged':
+ pass
+ elif this.state == 'done':
+ opp_obj.case_close(cr, uid, [record_id])
+ elif this.state == 'draft':
+ opp_obj.case_reset(cr, uid, [record_id])
+ elif this.state in ['cancel', 'open', 'pending']:
+ act = 'case_' + this.state
+ getattr(opp_obj, act)(cr, uid, [record_id])
+ return {}
+
+ _columns = {
+ 'opportunity_ids' : fields.many2many('crm.lead', 'merge_opportunity_rel', 'merge_id', 'opportunity_id', 'Opportunities', domain=[('type', '=', 'opportunity')]),
+ 'state': fields.selection(crm.AVAILABLE_STATES + [('unchanged', 'Unchanged')], string='Set State To', required=True),
+ }
+
+ def default_get(self, cr, uid, fields, context=None):
+ """
+ This function gets default values
+ @param self: The object pointer
+ @param cr: the current row, from the database cursor,
+ @param uid: the current user’s ID for security checks,
+ @param fields: List of fields for default value
+ @param context: A standard dictionary for contextual values
+
+ @return : default values of fields.
+ """
+ record_id = context and context.get('active_id', False) or False
+ res = super(crm_merge_opportunity, self).default_get(cr, uid, fields, context=context)
+
+ if record_id:
+ opp_obj = self.pool.get('crm.lead')
+ opp = opp_obj.browse(cr, uid, record_id, context=context)
+ opp_ids = opp_obj.search(cr, uid, [('partner_id', '=', opp.partner_id.id), ('type', '=', 'opportunity'), ('state', 'in', ('open', 'pending'))])
+ # Removing current opportunity
+ if record_id in opp_ids:
+ opp_ids.remove(record_id)
+
+ if 'opportunity_ids' in fields:
+ res.update({'opportunity_ids': opp_ids})
+ if 'state' in fields:
+ res.update({'state': u'cancel'})
+
+ return res
+
+crm_merge_opportunity()
+
+# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
diff --git a/addons/crm/wizard/crm_merge_opportunities_view.xml b/addons/crm/wizard/crm_merge_opportunities_view.xml
new file mode 100644
index 00000000000..5ee0eda5375
--- /dev/null
+++ b/addons/crm/wizard/crm_merge_opportunities_view.xml
@@ -0,0 +1,49 @@
+
+
+
+
+
+
+
+ crm.merge.opportunity.form
+ crm.merge.opportunity
+ form
+
+
+
+
+
+
+
+
+ Merge Opportunities
+ crm.merge.opportunity
+ form
+ form
+
+ new
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/addons/crm_claim/crm_claim.py b/addons/crm_claim/crm_claim.py
index 76a6073b58c..905b1bba9ff 100644
--- a/addons/crm_claim/crm_claim.py
+++ b/addons/crm_claim/crm_claim.py
@@ -52,12 +52,6 @@ class crm_claim(osv.osv, crm.crm_case):
"canall which is this opportunity source."),
'planned_revenue': fields.float('Planned Revenue'),
'planned_cost': fields.float('Planned Costs'),
- 'som': fields.many2one('res.partner.som', 'State of Mind', \
- help="The minds states allow to define a value scale "\
- "which represents the partner mentality in "\
- "relation to our services.The scale has to be "\
- "created with a factor for each level from 0 "\
- "(Very dissatisfied) to 10 (Extremely satisfied)"),
'categ_id': fields.many2one('crm.case.categ', 'Category', \
domain="[('section_id','=',section_id),\
('object_id.model', '=', 'crm.claim')]"),
diff --git a/addons/crm_claim/report/crm_claim_report.py b/addons/crm_claim/report/crm_claim_report.py
index 18c6d16ed53..fed4026aa02 100644
--- a/addons/crm_claim/report/crm_claim_report.py
+++ b/addons/crm_claim/report/crm_claim_report.py
@@ -107,7 +107,7 @@ class crm_claim_report(osv.osv):
group by to_char(c.create_date, 'YYYY'), to_char(c.create_date, 'MM'), \
c.state, c.user_id,c.section_id, c.stage_id,\
c.categ_id,c.partner_id,c.company_id,c.create_date,to_char(c.create_date, 'YYYY-MM-DD')
- ,c.priority,c.type_id,c.som
+ ,c.priority,c.type_id
)""")
crm_claim_report()
diff --git a/addons/crm_fundraising/crm_fundraising.py b/addons/crm_fundraising/crm_fundraising.py
index 81e16a47ac3..962fae07fd3 100644
--- a/addons/crm_fundraising/crm_fundraising.py
+++ b/addons/crm_fundraising/crm_fundraising.py
@@ -75,11 +75,6 @@ class crm_fundraising(osv.osv, crm.crm_case):
"modes available with the customer." \
" With each commercial opportunity, you can indicate\
the canall which is this opportunity source."),
- 'som': fields.many2one('res.partner.som', 'State of Mind', \
- help="The minds states allow to define a value scale which represents" \
- "the partner mentality in relation to our services.The scale has" \
- "to be created with a factor for each level from 0 \
- (Very dissatisfied) to 10 (Extremely satisfied)."),
'state': fields.selection(crm.AVAILABLE_STATES, 'State', size=16, readonly=True,
help='The state is set to \'Draft\', when a case is created.\
\nIf the case is in progress the state is set to \'Open\'.\
diff --git a/addons/crm_helpdesk/crm_helpdesk.py b/addons/crm_helpdesk/crm_helpdesk.py
index d4a1e9d59fc..9c223c74a54 100644
--- a/addons/crm_helpdesk/crm_helpdesk.py
+++ b/addons/crm_helpdesk/crm_helpdesk.py
@@ -61,11 +61,6 @@ class crm_helpdesk(osv.osv, crm.crm_case):
'planned_cost': fields.float('Planned Costs'),
'priority': fields.selection(crm.AVAILABLE_PRIORITIES, 'Priority'),
'probability': fields.float('Probability (%)'),
- 'som': fields.many2one('res.partner.som', 'State of Mind', \
- help="The minds states allow to define a value scale which represents" \
- "the partner mentality in relation to our services.The scale has" \
- "to be created with a factor for each level from 0" \
- "(Very dissatisfied) to 10 (Extremely satisfied)."),
'categ_id': fields.many2one('crm.case.categ', 'Category', \
domain="[('section_id','=',section_id),\
('object_id.model', '=', 'crm.helpdesk')]"),
diff --git a/addons/crm_helpdesk/crm_helpdesk_demo.xml b/addons/crm_helpdesk/crm_helpdesk_demo.xml
index fd31bb4c8fb..be8da99f140 100644
--- a/addons/crm_helpdesk/crm_helpdesk_demo.xml
+++ b/addons/crm_helpdesk/crm_helpdesk_demo.xml
@@ -3,7 +3,6 @@
-
@@ -17,7 +16,6 @@
-
@@ -31,7 +29,6 @@
-
@@ -46,7 +43,6 @@
-
diff --git a/addons/crm_profiling/crm_profiling_view.xml b/addons/crm_profiling/crm_profiling_view.xml
index eeb95d77fc1..e0dbcce05a1 100644
--- a/addons/crm_profiling/crm_profiling_view.xml
+++ b/addons/crm_profiling/crm_profiling_view.xml
@@ -16,7 +16,7 @@
tree,form
-
@@ -26,7 +26,7 @@
tree,form
-
diff --git a/addons/hr_attendance/test/test_hr_attendance.yml b/addons/hr_attendance/test/test_hr_attendance.yml
index 5c1132525f5..e4a08476985 100644
--- a/addons/hr_attendance/test/test_hr_attendance.yml
+++ b/addons/hr_attendance/test/test_hr_attendance.yml
@@ -1,8 +1,8 @@
-- |
- In order to test hr_attendance module in OpenERP, I create new attendance and perform Sign In/Sign Out operation.
-
-- |
- First I create Employee "Mark Johnson".
+-
+ In order to test hr_attendance module in OpenERP, I will first create new attendance reasons and perform Sign In/Sign Out operations.
+
+-
+ I create a new employee "Mark Johnson".
-
!record {model: hr.employee, id: hr_employee_employee0}:
address_home_id: base.res_partner_address_1
@@ -10,56 +10,56 @@
gender: male
name: Mark Johnson
user_id: base.user_root
-
-- |
- Given that I have Attendance Reason "Good Morning" for Sign In.
--
- !record {model: hr.action.reason, id: hr_action_reason_goodmorning0}:
- name: Good Morning
+
+-
+ I create a new attendance reason "Login" for Sign In.
+-
+ !record {model: hr.action.reason, id: hr_action_reason_login0}:
+ name: Login
action_type: sign_in
-- |
- I also create another Attendance Reason for Sign Out.
--
- !record {model: hr.action.reason, id: hr_action_reason_goodnight0}:
- name: Good Night
+-
+ I create second attendance reason "Logout" for Sign Out.
+-
+ !record {model: hr.action.reason, id: hr_action_reason_logout0}:
+ name: Logout
action_type: sign_out
-- |
- Now , When I came in office , I create Atendances and perform "Sign In" action with proper reason.
--
+-
+ Now, at the time of login, I create an attendance with "Sign In" action and proper reason.
+-
!record {model: hr.attendance, id: hr_attendance_0}:
action: sign_in
- action_desc: 'hr_action_reason_goodmorning0'
+ action_desc: 'hr_action_reason_login0'
employee_id: 'hr_employee_employee0'
name: '2010-05-18 19:08:08'
-- |
- I check that Employee is in "Present" state.
-
- !assert {model: hr.employee, id: hr_employee_employee0}:
+ I check that Employee state is "Present".
+-
+ !assert {model: hr.employee, id: hr_employee_employee0}:
- state == 'present'
-
-- |
- When I left office , I create attendance and perform "Sign Out".
--
+
+-
+ At the time of logout, I create an attendance with "Sign Out" action.
+-
!record {model: hr.attendance, id: hr_attendance_1}:
action: sign_out
employee_id: 'hr_employee_employee0'
name: '2010-05-18 19:10:55'
-- |
- I check that Employee is in "Absent" state.
-
- !assert {model: hr.employee, id: hr_employee_employee0}:
- - state == 'absent'
+ I check that Employee state is Absent.
+-
+ !assert {model: hr.employee, id: hr_employee_employee0}:
+ - state == 'absent'
-- |
- I can also fill my attendance using "Sign In/Sign Out" wizard.
--
+-
+ I will use "Sign In/Sign Out" wizard for attendances.
+-
!record {model: hr.sign.in.out, id: hr_sign_in_out_markjohnson0}:
name: Mark Johnson
state: absent
-
-- |
- I click on "Sign In" button of this wizard to perform present action.
--
+
+-
+ I click on "Sign In" button of this wizard to login.
+-
!python {model: hr.sign.in.out}: |
obj_attendance = self.pool.get('hr.employee')
emp_id = obj_attendance.search(cr, uid, [('user_id', '=', uid), ('name', '=', "Mark Johnson")])
@@ -68,21 +68,21 @@
self.write(cr, uid, [ref('hr_sign_in_out_markjohnson0')], {'name': employee['name'], 'state': employee['state'], 'emp_id': emp_id[0]})
self.si_check(cr, uid, [ref("hr_sign_in_out_markjohnson0")], {"active_id": ref("hr_employee_employee0")})
-- |
- I check that Employee is in "Present" state.
+-
+ I check that Employee state is "Present".
-
!assert {model: hr.employee, id: hr_employee_employee0}:
- - state == 'present'
-
-- |
- I forgot to "Sign Out" in Yesterday and want to sign in Today using This wizard.
--
+ - state == 'present'
+
+-
+ I forgot to "Sign Out" Yesterday and want to sign in Today using This wizard.
+-
!record {model: hr.sign.in.out, id: hr_sign_in_out_markjohnson0}:
name: Mark Johnson
state: present
-- |
- I click on "Sign In" button of this wizard. that will Open new form which ask for Last Sign Out date.
--
+-
+ I click on "Sign In" button of this wizard, this will Open a new form which ask for Last Sign Out date.
+-
!python {model: hr.sign.in.out}: |
obj_attendance = self.pool.get('hr.employee')
emp_id = obj_attendance.search(cr, uid, [('user_id', '=', uid), ('name', '=', "Mark Johnson")])
@@ -90,15 +90,15 @@
employee = obj_attendance.read(cr, uid, emp_id)[0]
self.write(cr, uid, [ref('hr_sign_in_out_markjohnson0')], {'name': employee['name'], 'state': employee['state'], 'emp_id': emp_id[0]})
self.si_check(cr, uid, [ref("hr_sign_in_out_markjohnson0")])
-- |
- I select Last Sign Out date in "hr sign out ask" wizard.
--
+-
+ I select Last Sign Out date.
+-
!record {model: hr.sign.in.out.ask, id: hr_sign_in_out_ask_markjohnson0}:
last_time: !eval time.strftime('%Y-%m-%d %H:%M:%S')
- name: Mark Johnson
-- |
- Now I click on "Sign In" button of this wizard.
--
+ name: Mark Johnson
+-
+ Now I click on "Sign In" button of this wizard.
+-
!python {model: hr.sign.in.out.ask}: |
obj_attendance = self.pool.get('hr.employee')
emp_id = obj_attendance.search(cr, uid, [('user_id', '=', uid), ('name', '=', "Mark Johnson")])
@@ -106,4 +106,11 @@
employee = obj_attendance.read(cr, uid, emp_id)[0]
self.write(cr, uid, [ref('hr_sign_in_out_ask_markjohnson0')], {'emp_id': emp_id[0]})
#self.sign_in(cr, uid, [ref("hr_sign_in_out_ask_markjohnson0")], {"active_ids": [ref("hr_attendance.menu_hr_attendance_sigh_in_out")]})
-
\ No newline at end of file
+
+-
+ Finally i will check the state of the employee is present.
+-
+ !record {model: hr.sign.in.out, id: hr_sign_in_out_markjohnson0}:
+ name: Mark Johnson
+ state: present
+
diff --git a/addons/hr_contract/test/test_hr_contract.yml b/addons/hr_contract/test/test_hr_contract.yml
index cbcc7e67fda..084e45620a4 100644
--- a/addons/hr_contract/test/test_hr_contract.yml
+++ b/addons/hr_contract/test/test_hr_contract.yml
@@ -1,9 +1,8 @@
-- |
- In order to test hr_contract module in OpenERP,
- I will create contract for "Mark Johnson" employee.
-
-- |
- I create Employee "Mark Johnson" to assign contract.
+-
+ In order to test hr_contract module in OpenERP, I will create a new employee and create contract for the same.
+
+-
+ I create a new employee "Mark Johnson".
-
!record {model: hr.employee, id: hr_employee_employee0}:
address_home_id: base.res_partner_address_1
@@ -11,29 +10,31 @@
gender: male
name: Mark Johnson
user_id: base.user_root
-
-- |
- Given that I have Contract wage period "monthly" and
- specify "hours in period" is "176.00"
--
+ children: 2
+ marital: hr.hr_employee_marital_status_married
+ place_of_birth: Belgium
+ vehicle: 'No'
+ vehicle_distance: 12
+
+
+-
+ I create a new Contract wage period.
+-
!record {model: hr.contract.wage.type.period, id: hr_contract_wage_type_period_monthly0}:
- factor_days: 178.0
+ factor_days: 176.0
name: monthly
-- |
- Given that I have Contract wage type "Monthly Gross Wage".
- select wage period "monthly" and type "Gross". with hour cost "1.9"
--
+-
+ I create a new Contract Wage Type.
+-
!record {model: hr.contract.wage.type, id: hr_contract_wage_type_monthlygrosswage0}:
factor_type: 1.9
name: Monthly Gross Wage
period_id: 'hr_contract_wage_type_period_monthly0'
type: gross
-
-- |
- Now I start by creating contract for "Mark Johnson".
- Select wage type "Monthly Gross Wage" and Wage period "monthly"
- which I had given.
--
+
+-
+ I create a new contract for "Mark Johnson".
+-
!record {model: hr.contract, id: hr_contract_contract0}:
advantages_gross: 0.0
employee_id: 'hr_employee_employee0'
diff --git a/addons/hr_holidays/test/test_hr_holiday.yml b/addons/hr_holidays/test/test_hr_holiday.yml
index 68d58b1791b..03c1666dc6f 100644
--- a/addons/hr_holidays/test/test_hr_holiday.yml
+++ b/addons/hr_holidays/test/test_hr_holiday.yml
@@ -1,8 +1,8 @@
-- |
- In order to test the hr_holiday in OpenERP, I will Allocate leaves for Employee and manage leaves and leaves requests.
-- |
- For that First I create new user "user1" to make leave request.
--
+-
+ In order to test the hr_holiday module in OpenERP, I will Allocate leaves for Employee and manage leaves and leaves requests.
+-
+ I create new user "user1" to who makes leave request.
+-
!record {model: res.users, id: res_users_user0}:
company_id: base.main_company
context_lang: en_US
@@ -13,7 +13,7 @@
login: user1
name: user1
password: user1
-- |
+-
I create a new employee “Mark Johnshon” as Manager to validate employee leave.
-
!record {model: hr.employee, id: hr_employee_employee0}:
@@ -22,90 +22,87 @@
gender: male
name: Mark Johnson
user_id: base.user_root
-- |
- Create another employee "Phil Graves" as "user1" who make leave request.
--
+-
+ I Create another employee "Phil Graves" as "user1".
+-
!record {model: hr.employee, id: hr_employee_philgraves0}:
address_home_id: base.res_partner_address_8
name: Phil Graves
parent_id: 'hr_employee_employee0'
user_id: 'res_users_user0'
-- |
- Given that I have Leave type for employee.
--
- !record {model: hr.holidays.status, id: hr_holidays_status_fullleave0}:
+-
+ I create a new Leave type "Sick Leave".
+-
+ !record {model: hr.holidays.status, id: hr_holidays_status_sick0}:
color_name: red
- name: Full Leave.
- limit: 1
+ name: Sick Leave.
+ limit: 12
-- |
- After that I allocate leave request for employee "Phil Graves".
--
+-
+ I allocate leave request for employee "Phil Graves".
+-
!record {model: hr.holidays, id: hr_holidays_allocateleaveforuser0}:
allocation_type: employee
employee_id: 'hr_employee_philgraves0'
- holiday_status_id: hr_holidays_status_fullleave0
- name: Allocate leave for user1
+ holiday_status_id: hr_holidays_status_sick0
+ name: Sick Leaves for Phil Graves
number_of_days_temp: 12.0
date_from: '05/20/2010 13:59:00'
date_to: '05/22/2010 13:59:00'
type: add
-- |
- I click on "Confirm" button to confirm allocate leave for employee.
--
- !workflow {model: hr.holidays, action: confirm, ref: hr_holidays_allocateleaveforuser0}
-
-- |
- I click on "Validate" button to validate leave for employee.
-
- !workflow {model: hr.holidays, action: validate, ref: hr_holidays_allocateleaveforuser0}
+ I confirmed the allocation by clicking on "Confirm" button.
+-
+ !workflow {model: hr.holidays, action: confirm, ref: hr_holidays_allocateleaveforuser0}
-- |
- Now employee "Phil Graves" want to leave. so, I connect as user1 which is username of this employee and want to make leave request.
--
+-
+ I validate the allocation by clicking on "To Approve" button.
+-
+ !workflow {model: hr.holidays, action: validate, ref: hr_holidays_allocateleaveforuser0}
+
+-
+ I connect as "user1", and create a new leave request for employee "Phil Graves".
+-
!record {model: hr.holidays, id: hr_holidays_iwanttoleaveforgotohospital0}:
allocation_type: employee
date_from: '2010-05-20 11:48:00'
date_to: '2010-05-21 11:48:00'
employee_id: 'hr_employee_philgraves0'
- holiday_status_id: 'hr_holidays_status_fullleave0'
- name: I want to leave for go to hospital
- notes: I want to leave for go to hospital. so please accept my leave.
+ holiday_status_id: 'hr_holidays_status_sick0'
+ name: Appointment with Doctor
+ notes: My appointment with the doctor is confirmed. so please accept my leave.
number_of_days_temp: 2.0
type: remove
user_id: 'res_users_user0'
-- |
- I check that Leave Request is on "Draft" state.
+-
+ I check that Leave Request is in "Draft" state.
-
!assert {model: hr.holidays, id: hr_holidays_iwanttoleaveforgotohospital0}:
- - state == 'draft'
-
-- |
- I confirm my leave Request by click on "Confirm" button.
--
+ - state == 'draft'
+
+-
+ I confirm leave Request by click on "Confirm" button.
+-
!workflow {model: hr.holidays, action: confirm, ref: hr_holidays_iwanttoleaveforgotohospital0}
-
-- |
- I connect as Admin user and Open Leave request of "Phil Graves".
- and "validate" it by click on "validate" button.
--
+
+-
+ I connect as "Admin" user and Open Leave request of "Phil Graves" and "validate" it by click on "Approve" button.
+-
!workflow {model: hr.holidays, action: validate, ref: hr_holidays_iwanttoleaveforgotohospital0}
-
-- |
- I check that "Leave Manager" field is automaticly filled by the user who validate the leave'.
+
+-
+ I check that "Leave Manager" field is automatically filled by the user who validate the leave'.
-
!python {model: hr.holidays}: |
ids2 = self.pool.get('hr.employee').search(cr, uid, [('user_id','=', uid)])
obj = self.browse(cr, uid, ref('hr_holidays_iwanttoleaveforgotohospital0'))
assert ids2[0] == obj.manager_id.id
-
-- |
+
+-
I check that Leave request state is "Validated".
--
+-
!assert {model: hr.holidays, id: hr_holidays_iwanttoleaveforgotohospital0}:
- - state == "validate"
-
-- |
- I can also see Summary of Employee's holiday by using 'Print Summary of Employee's Holidays'.
- This will allow you to choose if you want to print either the Confirmed & Validated holidays or only the Validated ones.
-
\ No newline at end of file
+ - state == "validate"
+
+-
+ I can also see Summary of Employee's holiday by using 'Employee's Holidays' Report. This report will allows to choose to print holidays with state Confirmed, Validated or both.
diff --git a/addons/hr_timesheet/test/test_hr_timesheet.yml b/addons/hr_timesheet/test/test_hr_timesheet.yml
index 2b5a924805a..43143e4e324 100644
--- a/addons/hr_timesheet/test/test_hr_timesheet.yml
+++ b/addons/hr_timesheet/test/test_hr_timesheet.yml
@@ -1,9 +1,9 @@
-- |
- In order to test hr_timesheet Module in OpenERP, I make "Sign In or Sign Out for Project" to encode and
- track time spent on the different projects.
+-
+ In order to test hr_timesheet Module in OpenERP, I make "Sign In/Sign Out for Project" to encode and
+ track time spent on the different projects.
-- |
- Now, I create a new employee “Mark Johnson” to test Timesheet.
+-
+ I create a new employee “Mark Johnson” to test Timesheet.
-
!record {model: hr.employee, id: hr_employee_employee0}:
address_home_id: base.res_partner_address_1
@@ -13,8 +13,8 @@
name: Mark Johnson
user_id: base.user_root
-- |
- I create new user "user1" which is assigned to employee.
+-
+ I create new user "user1".
-
!record {model: res.users, id: res_users_user0}:
company_id: base.main_company
@@ -29,8 +29,8 @@
name: user1
password: user1
-- |
- I create another employee "Francline" as "user1".
+-
+ I create another new employee "Francline" as "user1".
-
!record {model: hr.employee, id: hr_employee_fracline1}:
address_home_id: base.res_partner_address_8
@@ -38,16 +38,16 @@
parent_id: 'hr_employee_employee0'
user_id: 'res_users_user0'
-- |
- Given that I have Timesheet journal for employee.
+-
+ I create Timesheet journal for employee.
-
!record {model: account.analytic.journal, id: analytic_journal}:
code: TS
name: Timesheet Journal
type: general
-- |
- Given that I have product for "Consultancy - Senior Developer".
+-
+ I create a product as "Consultancy - Senior Developer".
-
!record {model: product.product, id: product_consultant}:
categ_id: product.product_category_10
@@ -62,42 +62,41 @@
uom_id: product.uom_hour
uom_po_id: product.uom_hour
-- |
- I assing product and journal to "Mark Johnson"
+-
+ I assigned product and journal to "Mark Johnson"
-
!record {model: hr.employee, id: hr_employee_employee0}:
product_id: product_consultant
journal_id: analytic_journal
-- |
- And also assing product and journal to "francline" employee.
+-
+ I assigned product and journal to "Francline".
-
!record {model: hr.employee, id: hr_employee_fracline1}:
product_id: product_consultant
journal_id: analytic_journal
-- |
- Now , When I came in office , I create Attendances and perform "Sign In" action with proper reason.
+-
+ I create attendance and perform "Sign In" action with proper reason.
-
!record {model: hr.attendance, id: hr_attendance_0}:
action: sign_in
employee_id: 'hr_employee_fracline1'
name: '2010-05-26 10:08:08'
-- |
- When I left office , I create attendance and perform "Sign Out".
+-
+ I create attendance and perform "Sign Out" action.
-
!record {model: hr.attendance, id: hr_attendance_1}:
action: sign_out
employee_id: 'hr_employee_fracline1'
name: '2010-05-26 15:10:55'
-
-- |
- I start by "Sign In/Sign Out by Project" wizard and click on "Sign In/Sign Out" button of this wizard.
+-
+ On "Sign In/Sign Out by Project" wizard i click on "Sign In/Sign Out" button of this wizard.
-
!python {model: hr.sign.in.project}: |
uid = ref('res_users_user0')
self.check_state(cr, uid, [ref("hr_employee_fracline1")], {"active_ids": [ref("hr_timesheet.menu_hr_timesheet_sign_in")]})
-- |
+-
I select start date and Perform start work on project.
-
!python {model: hr.sign.in.project}: |
@@ -105,8 +104,8 @@
new_id = self.create(cr, uid, {'emp_id': 'hr_employee_fracline1', 'name': 'Francline', 'server_date': '2010-06-08 19:50:54', 'state': 'absent'})
self.sign_in_result(cr, uid, [new_id], context)
-- |
- My work is done and I want to stop work.for that I click on "Sign In/Sign Out" button of "Sign In/Sign Out by Project" wizard.
+-
+ To stop work I click on "Sign In/Sign Out" button of "Sign In/Sign Out by Project" wizard.
Which check state in hr attendace form for user.
-
!python {model: hr.sign.in.project}: |
@@ -115,11 +114,9 @@
self.check_state(cr, uid, ids, {"active_ids": [ref("hr_timesheet.menu_hr_timesheet_sign_in")]
})
-- |
- This will Open "hr sign out project" form. I select analytical project2 development account.
--
- For that I Creating a analytic account.
--
+-
+ I Create an analytic account "Project2".
+-
!record {model: account.analytic.account, id: account_analytic_account_project0}:
company_id: base.main_company
name: Project2
@@ -127,8 +124,8 @@
quantity_max: 0.0
state: open
-- |
- My work for this project is over and I stop work by click on "Stop Work" button of this wizard.
+-
+ My work for this project is over and I stop working by clicking on "Stop Work" button of this wizard.
-
!python {model: hr.sign.out.project}: |
import time
diff --git a/addons/hr_timesheet_sheet/test/test_hr_timesheet_sheet.yml b/addons/hr_timesheet_sheet/test/test_hr_timesheet_sheet.yml
index 38186031028..c21a5b36ebb 100644
--- a/addons/hr_timesheet_sheet/test/test_hr_timesheet_sheet.yml
+++ b/addons/hr_timesheet_sheet/test/test_hr_timesheet_sheet.yml
@@ -1,55 +1,36 @@
-- |
- In order, to test hr_timesheet_sheet module in OpenERP, I create timesheet and check validation process done by
- manager.
-
-- |
- Now, I create a new employee “Mark Johnson” to test Timesheet.
+-
+ In order to test hr_timesheet_sheet module in OpenERP, I create timesheet and check validation process done by manager.
+-
+ I will create a company and set maximum allowed difference between timesheet and attendance to 1 hour
+-
+ !record {model: res.company, id: res_company_openERP}:
+ currency_id: base.ARS
+ name: OpenERP SA
+ partner_id: base.res_partner_desertic_hispafuentes
+ timesheet_max_difference: 1.0
+
+-
+ I create a new employee “Mark Johnson”.
-
!record {model: hr.employee, id: hr_employee_employee0}:
address_home_id: base.res_partner_address_1
- company_id: base.main_company
+ company_id: res_company_openERP
gender: male
marital: hr.hr_employee_marital_status_single
name: Mark Johnson
user_id: base.user_root
-
-- |
- I create new user "user1".
--
- !record {model: res.users, id: res_users_user0}:
- company_id: base.main_company
- context_lang: en_US
- groups_id:
- - hr.group_hr_user
- - hr_attendance.group_hr_attendance
- - base.group_user
- - base.group_extended
- - hr.group_hr_manager
- login: user1
- name: user1
- password: user1
-- |
- create another employee "Francline" as "user1".
--
- !record {model: hr.employee, id: hr_employee_fracline0}:
- address_home_id: base.res_partner_address_8
- name: Francline
- parent_id: 'hr_employee_employee0'
- user_id: 'res_users_user0'
-
-- |
- Given that I have Timesheet journal for employee.
-
--
+-
+ I create new Timesheet journal for employee.
+-
!record {model: account.analytic.journal, id: analytic_journal}:
code: TS
name: Timesheet Journal
type: general
-
-- |
- Given that I have product for "Consultancy - Senior Developer".
--
+
+-
+ I create a new product "Consultancy - Senior Developer".
+-
!record {model: product.product, id: product_consultant}:
categ_id: product.product_category_10
default_code: DEV
@@ -63,77 +44,110 @@
uom_id: product.uom_hour
uom_po_id: product.uom_hour
-- |
- I assing product and journal to "Mark Johnson"
--
+-
+ I assign this product and journal to "Mark Johnson"
+-
!record {model: hr.employee, id: hr_employee_employee0}:
- product_id: product_consultant
+ product_id: product_consultant
journal_id: analytic_journal
-- |
- And also assing product and journal to "francline" employee.
--
- !record {model: hr.employee, id: hr_employee_fracline0}:
- product_id: product_consultant
- journal_id: analytic_journal
-
-- |
- I connect as "francline" and create my current timesheet.
--
+
+-
+ I create my current timesheet for "Mark Johnson".
+-
!record {model: hr_timesheet_sheet.sheet, id: hr_timesheet_sheet_sheet_deddk0}:
date_current: '2010-05-26'
date_from: '2010-05-01'
date_to: '2010-05-31'
name: Week-22(2010)
state: new
- user_id: 'res_users_user0'
-- |
- Now , When I came in office , I create Attendances and perform "Sign In" action with proper reason.
--
+ user_id: base.user_root
+-
+ Now , at the time of login, I create Attendances and perform "Sign In" action.
+-
!record {model: hr.attendance, id: hr_attendance_0}:
action: sign_in
- employee_id: 'hr_employee_fracline0'
+ employee_id: 'hr_employee_employee0'
name: '2010-05-26 10:08:08'
-
-- |
- When I left office , I create attendance and perform "Sign Out".
--
+
+-
+ At the time of logout, I create attendance and perform "Sign Out".
+-
!record {model: hr.attendance, id: hr_attendance_1}:
action: sign_out
- employee_id: 'hr_employee_fracline0'
+ employee_id: 'hr_employee_employee0'
name: '2010-05-26 15:10:55'
--
- I create Timesheet Entry for time spend on today work.
-
-
+ I create Timesheet Entry for time spend on today work.
+
+-
!record {model: hr_timesheet_sheet.sheet, id: hr_timesheet_sheet.sheet1}:
timesheet_ids:
- account_id: account.analytic_sednacom
date: '05/26/2010'
name: 'Develop yaml for hr module'
- unit_amount: 5.00
+ unit_amount: 3.00
amount: -90.00
product_id: hr_timesheet.product_consultant
general_account_id: account.a_expense
- user_id: res_users_user0
- journal_id: hr_timesheet.analytic_journal
-
-- |
- I confirm my timesheet at end of period by click on "Confirm" button which is signal of workflow.
--
- !python {model: hr_timesheet_sheet.sheet}: |
- uid = ref('res_users_user0')
- self.button_confirm(cr, uid, [ref('hr_timesheet_sheet_sheet_deddk0')])
-- |
- I check that state is "Confirmed".
--
- !assert {model: hr_timesheet_sheet.sheet, id: hr_timesheet_sheet_sheet_deddk0}:
- - state == 'confirm'
-- |
- "Mark Johnson" check timesheet and time spend on project by "francline" employee.
- And then accept it request by click on "Accept" button.If "Maximal difference between timesheet and attendances" is more than 1 then manage can "Refuse" his request.
-
+ user_id: base.user_root
+ journal_id: hr_timesheet.analytic_journal
-
- !python {model: hr_timesheet_sheet.sheet}: |
- self.write(cr, uid, [ref('hr_timesheet_sheet_sheet_deddk0')], {'state': 'done'})
\ No newline at end of file
+ I confirm my timesheet at end of period by click on "Confirm" button,
+ if the difference between timesheet hour and attendance hour is more than 1 hour it will give message.
+-
+ !python {model: hr_timesheet_sheet.sheet}: |
+ uid = ref('base.user_root')
+ for sheet in self.browse(cr, uid, [ref('hr_timesheet_sheet_sheet_deddk0')]):
+ di = sheet.user_id.company_id.timesheet_max_difference
+ if (abs(sheet.total_difference) < di) or not di:
+ wf_service = netsvc.LocalService("workflow")
+ wf_service.trg_validate(uid, 'hr_timesheet_sheet.sheet', sheet.id, 'confirm', cr)
+ else:
+ print "Please verify that the total difference of the sheet is lower than %.2f" %di
+
+-
+ I Modified the timesheet record.
+-
+ !record {model: hr_timesheet_sheet.sheet, id: hr_timesheet_sheet.sheet1}:
+ timesheet_ids:
+ - account_id: account.analytic_sednacom
+ date: '05/26/2010'
+ name: 'Develop yaml for hr module'
+ unit_amount: 2.0
+ amount: -90.00
+ product_id: hr_timesheet.product_consultant
+ general_account_id: account.a_expense
+ user_id: base.user_root
+ journal_id: hr_timesheet.analytic_journal
+
+-
+ I tried again to confirm the timesheet after modification.
+-
+ !python {model: hr_timesheet_sheet.sheet}: |
+ uid = ref('base.user_root')
+ self.button_confirm(cr, uid, [ref('hr_timesheet_sheet_sheet_deddk0')], {"lang": 'en_US', "active_ids":
+ [ref("hr_timesheet_sheet.menu_act_hr_timesheet_sheet_form")], "tz": False, "active_model":
+ "ir.ui.menu", "department_id": False, "section_id": False, "search_default_my_timesheet":
+ 1, "search_default_user_id": 1, "project_id": False, "active_id": ref("hr_timesheet_sheet.menu_act_hr_timesheet_sheet_form"),
+ })
+
+-
+ This time timesheet confirmed successfully.
+ I check that state is "Confirmed".
+-
+ !assert {model: hr_timesheet_sheet.sheet, id: hr_timesheet_sheet_sheet_deddk0}:
+ - state == 'confirm'
+-
+ The manager will accept This request by click on "Accept" button.
+
+-
+ !python {model: hr_timesheet_sheet.sheet}: |
+ self.write(cr, uid, [ref('hr_timesheet_sheet_sheet_deddk0')], {'state': 'done'})
+-
+ I check that state is "Done".
+-
+ !assert {model: hr_timesheet_sheet.sheet, id: hr_timesheet_sheet_sheet_deddk0}:
+ - state == 'done'
+
diff --git a/addons/l10n_ch/account_journal_view.xml b/addons/l10n_ch/account_journal_view.xml
index aa5d6c20080..5e681131e9c 100644
--- a/addons/l10n_ch/account_journal_view.xml
+++ b/addons/l10n_ch/account_journal_view.xml
@@ -8,24 +8,32 @@
+
+ Configure Your Account Journal System
+
+
+ Set accounts on financial journals defined by CamptoCamp l10n_ch module
+ 150
+
+
+ 15
+
+
-
-
-
-
-
-
-
+
+
+
+
+
- Next
+ Next
diff --git a/addons/mail_gateway/mail_gateway_view.xml b/addons/mail_gateway/mail_gateway_view.xml
index a9a2d1f96fc..fb70a08efc3 100644
--- a/addons/mail_gateway/mail_gateway_view.xml
+++ b/addons/mail_gateway/mail_gateway_view.xml
@@ -177,7 +177,7 @@
-
+
diff --git a/addons/mrp/mrp.py b/addons/mrp/mrp.py
index 51578408499..813133385be 100644
--- a/addons/mrp/mrp.py
+++ b/addons/mrp/mrp.py
@@ -533,33 +533,46 @@ class mrp_production(osv.osv):
return {'value': {'location_dest_id': src}}
return {}
- def product_id_change(self, cr, uid, ids, product, context=None):
+ def product_id_change(self, cr, uid, ids, product_id, context=None):
""" Finds UoM of changed product.
- @param product: Id of changed product.
+ @param product_id: Id of changed product.
@return: Dictionary of values.
"""
- if not product:
+ if not product_id:
return {'value': {
'product_uom': False,
- 'bom_id': False
+ 'bom_id': False,
+ 'routing_id': False
}}
- res = self.pool.get('product.product').browse(cr, uid, product, context=context)
+ bom_obj = self.pool.get('mrp.bom')
+ product = self.pool.get('product.product').browse(cr, uid, product_id, context=context)
+ bom_id = bom_obj._bom_find(cr, uid, product.id, product.uom_id and product.uom_id.id, [])
+ routing_id = False
+ if bom_id:
+ bom_point = bom_obj.browse(cr, uid, bom_id, context=context)
+ routing_id = bom_point.routing_id.id or False
result = {
- 'product_uom': res.uom_id and res.uom_id.id or False,
- 'bom_id': res.bom_ids and res.bom_ids[0].id or False
+ 'product_uom': product.uom_id and product.uom_id.id or False,
+ 'bom_id': bom_id,
+ 'routing_id': routing_id
}
return {'value': result}
- def bom_id_change(self, cr, uid, ids, product):
+ def bom_id_change(self, cr, uid, ids, bom_id, context=None):
""" Finds routing for changed BoM.
@param product: Id of product.
@return: Dictionary of values.
"""
- if not product:
- return {}
- res = self.pool.get('mrp.bom').read(cr, uid, [product], ['routing_id'])[0]
- routing_id = res['routing_id'] and res['routing_id'][0]
- result = {'routing_id': routing_id}
+ if not bom_id:
+ return {'value': {
+ 'routing_id': False
+ }}
+ bom_pool = self.pool.get('mrp.bom')
+ bom_point = bom_pool.browse(cr, uid, bom_id, context=context)
+ routing_id = bom_point.routing_id.id or False
+ result = {
+ 'routing_id': routing_id
+ }
return {'value': result}
def action_picking_except(self, cr, uid, ids):
diff --git a/addons/mrp/wizard/change_production_qty_view.xml b/addons/mrp/wizard/change_production_qty_view.xml
index b73d8bcc529..a9125afe41b 100644
--- a/addons/mrp/wizard/change_production_qty_view.xml
+++ b/addons/mrp/wizard/change_production_qty_view.xml
@@ -10,8 +10,11 @@
form
@@ -45,7 +49,7 @@
tree
-
+
@@ -56,8 +60,12 @@
-
-
+
+
+
+
+
+
@@ -103,7 +111,7 @@
-
+
diff --git a/addons/olap/data/olap_cube_view.xml b/addons/olap/data/olap_cube_view.xml
index 706f9093b3f..4ffbab0ff60 100644
--- a/addons/olap/data/olap_cube_view.xml
+++ b/addons/olap/data/olap_cube_view.xml
@@ -76,14 +76,14 @@
olap.parameters.config.wizardform
-
@@ -284,59 +284,59 @@
Planning
-
-
+
+ draft
-
-
+
+
-
+ Web Design
-
-
+
+ draft
-
-
+
+
-
+ Development, Integration and Testing
-
-
+
+ draft
-
-
+
+
-
+ Website Deployment
-
-
+
+ draft
-
-
+
+
diff --git a/addons/project_long_term/test/schedule_phase_tasks.yml b/addons/project_long_term/test/schedule_phase_tasks.yml
index 7af72f05824..92286700e6c 100644
--- a/addons/project_long_term/test/schedule_phase_tasks.yml
+++ b/addons/project_long_term/test/schedule_phase_tasks.yml
@@ -16,7 +16,7 @@
Create phase 'Develop GUI' in Outlook
-
!record {model: project.phase, id: project_phase_phase0}:
- date_start: '2010-06-02 00:00:00'
+ date_start: '2010-06-02'
duration: 200.0
name: phase123
product_uom: product.uom_day
@@ -36,7 +36,6 @@
-
!record {model: project.task, id: project_task_t0}:
name: t1
- occupation_rate: 1.0
planned_hours: 20.0
remaining_hours: 20.0
state: draft
@@ -49,7 +48,6 @@
-
!record {model: project.task, id: project_task_t1}:
name: t2
- occupation_rate: 1.0
planned_hours: 25.0
remaining_hours: 25.0
state: draft
@@ -61,7 +59,6 @@
-
!record {model: project.task, id: project_task_t2}:
name: t3
- occupation_rate: 1.0
planned_hours: 30.0
remaining_hours: 30.0
state: draft
@@ -74,7 +71,6 @@
-
!record {model: project.task, id: project_task_3}:
name: t4
- occupation_rate: 1.0
planned_hours: 25.0
remaining_hours: 25.0
state: draft
diff --git a/addons/project_long_term/test/schedule_project_phases.yml b/addons/project_long_term/test/schedule_project_phases.yml
index 470f2dc2e48..7f59b476c65 100644
--- a/addons/project_long_term/test/schedule_project_phases.yml
+++ b/addons/project_long_term/test/schedule_project_phases.yml
@@ -10,7 +10,7 @@
Create a project phase 'Defining Client's Basic Idea of Project'
-
!record {model: project.phase, id: project_phase_definingclientsbasicideaofproject0}:
- date_start: '2010-06-02 00:00:00'
+ date_start: '2010-06-02'
duration: 15.0
name: "Defining Client's Basic Idea of Project"
product_uom: product.uom_day
@@ -22,7 +22,7 @@
Create project phase 'Establishing Project Feasibility'
-
!record {model: project.phase, id: project_phase_establishingprojectfeasibility0}:
- date_start: '2010-06-02 00:00:00'
+ date_start: '2010-06-02'
duration: 30.0
name: Establishing Project Feasibility
product_uom: product.uom_day
@@ -33,7 +33,7 @@
Create project phase 'Preparation of Engineering Designs'
-
!record {model: project.phase, id: project_phase_preparationofengineeringdesigns0}:
- date_start: '2010-06-02 00:00:00'
+ date_start: '2010-06-02'
duration: 100.0
name: Preparation of Engineering Designs
product_uom: product.uom_hour
@@ -45,7 +45,7 @@
Create project phase 'Procurement of Works and Goods'
-
!record {model: project.phase, id: project_phase_procurementofworksandgoods0}:
- date_start: '2010-06-02 00:00:00'
+ date_start: '2010-06-02'
duration: 24.0
name: Procurement of Works and Goods
product_uom: product.uom_hour
@@ -57,7 +57,7 @@
Create project phase 'Project Construction'
-
!record {model: project.phase, id: project_phase_projectconstruction0}:
- date_start: '2010-06-02 00:00:00'
+ date_start: '2010-06-02'
duration: 4320.0
name: Project Construction
product_uom: product.uom_hour
@@ -69,7 +69,7 @@
Create project phase 'Project Completion'
-
!record {model: project.phase, id: project_phase_projectcompletion0}:
- date_start: '2010-06-02 00:00:00'
+ date_start: '2010-06-02'
duration: 240.0
name: Project Completion
product_uom: product.uom_hour
diff --git a/addons/project_long_term/test/schedule_project_tasks.yml b/addons/project_long_term/test/schedule_project_tasks.yml
index 1a218b83ad6..012898b9860 100644
--- a/addons/project_long_term/test/schedule_project_tasks.yml
+++ b/addons/project_long_term/test/schedule_project_tasks.yml
@@ -17,7 +17,7 @@
Create phase 'Develop GUI' in Thunderbird
-
!record {model: project.phase, id: project_phase_phase1}:
- date_start: '2010-06-02 00:00:00'
+ date_start: '2010-06-02'
duration: 100.0
name: phase22
product_uom: product.uom_day
diff --git a/addons/project_long_term/wizard/project_compute_phases.py b/addons/project_long_term/wizard/project_compute_phases.py
index bc377a5af7d..e13d307aab2 100644
--- a/addons/project_long_term/wizard/project_compute_phases.py
+++ b/addons/project_long_term/wizard/project_compute_phases.py
@@ -103,20 +103,20 @@ class project_compute_phases(osv.osv_memory):
# Recalculate date_start and date_end
# according to constraints on date start and date end on phase
if phase.constraint_date_start and str(s_date) < phase.constraint_date_start:
- start_date = datetime.datetime.strptime(phase.constraint_date_start, '%Y-%m-%d %H:%M:%S')
+ start_date = datetime.datetime.strptime(phase.constraint_date_start, '%Y-%m-%d')
else:
start_date = s_date
if phase.constraint_date_end and str(e_date) > phase.constraint_date_end:
- end_date= datetime.datetime.strptime(phase.constraint_date_end, '%Y-%m-%d %H:%M:%S')
- date_start = phase.constraint_date_end[:-3]
+ end_date= datetime.datetime.strptime(phase.constraint_date_end, '%Y-%m-%d')
+ date_start = phase.constraint_date_end
else:
end_date = e_date
date_start = end_date
# Write the calculated dates back
ctx = context.copy()
ctx.update({'scheduler': True})
- phase_obj.write(cr, uid, [phase.id], {'date_start': start_date.strftime('%Y-%m-%d %H:%M:%S'),
- 'date_end': end_date.strftime('%Y-%m-%d %H:%M:%S')},
+ phase_obj.write(cr, uid, [phase.id], {'date_start': start_date.strftime('%Y-%m-%d'),
+ 'date_end': end_date.strftime('%Y-%m-%d')},
context=ctx)
# Recursive call till all the next phases scheduled
for phase in phase.next_phase_ids:
diff --git a/addons/project_long_term/wizard/project_schedule_tasks.py b/addons/project_long_term/wizard/project_schedule_tasks.py
index d3c42a983d0..df9f1aae7d4 100644
--- a/addons/project_long_term/wizard/project_schedule_tasks.py
+++ b/addons/project_long_term/wizard/project_schedule_tasks.py
@@ -92,7 +92,7 @@ class project_schedule_task(osv.osv_memory):
if task_ids:
task_ids.sort()
tasks = task_obj.browse(cr, uid, task_ids, context=context)
- start_date = str(phase.date_start)[:-9]
+ start_date = str(phase.date_start)
if not phase.date_start:
if not phase.project_id.date_start:
start_date = datetime.datetime.now().strftime("%Y-%m-%d")
diff --git a/addons/purchase/test/procurement_buy.yml b/addons/purchase/test/procurement_buy.yml
index 011e70d0cdc..69b4f1d6195 100644
--- a/addons/purchase/test/procurement_buy.yml
+++ b/addons/purchase/test/procurement_buy.yml
@@ -23,6 +23,7 @@
- delay: 1
name: base.res_partner_asus
qty: 5.0
+ min_qty:1.0
-
I create procurement order.
-
diff --git a/addons/sale/__init__.py b/addons/sale/__init__.py
index 3ad30a6233e..4d8541b4ab5 100644
--- a/addons/sale/__init__.py
+++ b/addons/sale/__init__.py
@@ -25,6 +25,7 @@
import sale
import stock
+import sale_installer
import product
import wizard
import report
diff --git a/addons/sale/__openerp__.py b/addons/sale/__openerp__.py
index d6943e617d0..bc9e073de01 100644
--- a/addons/sale/__openerp__.py
+++ b/addons/sale/__openerp__.py
@@ -61,6 +61,7 @@
'sale_sequence.xml',
'sale_data.xml',
'sale_view.xml',
+ 'sale_installer.xml',
'report/sale_report_view.xml',
'sale_report.xml',
'stock_view.xml',
@@ -69,12 +70,17 @@
],
'demo_xml': ['sale_demo.xml','board_sale_demo.xml'],
'test': [
- 'test/shipping_manual_sale_order.yml',
- 'test/prepaid_sale_order.yml',
+ 'test/data_test.yml',
+ 'test/manual_order_policy.yml',
+ 'test/prepaid_order_policy.yml',
+ 'test/picking_order_policy.yml',
+ 'test/postpaid_order_policy.yml',
'test/advance_invoice.yml',
'test/so_make_line_invoice.yml',
'test/so_make_invoice.yml',
'test/sale_procurement.yml',
+ 'test/invoice_on_ordered_qty.yml',
+ 'test/invoice_on_shipped_qty.yml',
],
'installable': True,
'active': False,
diff --git a/addons/sale/sale_installer.py b/addons/sale/sale_installer.py
new file mode 100644
index 00000000000..d85273fa9a0
--- /dev/null
+++ b/addons/sale/sale_installer.py
@@ -0,0 +1,44 @@
+# -*- coding: utf-8 -*-
+##############################################################################
+#
+# OpenERP, Open Source Management Solution
+# Copyright (C) 2004-2010 Tiny SPRL ().
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as
+# published by the Free Software Foundation, either version 3 of the
+# License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see .
+#
+##############################################################################
+from osv import fields, osv
+
+class sale_installer(osv.osv_memory):
+ _name = 'sale.installer'
+ _inherit = 'res.config.installer'
+
+ _columns = {
+ 'sale_analytic_plans': fields.boolean('Sales Analytic Distribution Management',
+ help="The base module to manage analytic distribution and sales orders."),
+ 'sale_journal': fields.boolean('Sales and deliveries by journal',
+ help="The sale journal modules allows you to categorise your "
+ "sales and deliveries (picking lists) between different journals. "
+ "This module is very helpful for bigger companies that "
+ "works by departments."),
+ 'sale_layout': fields.boolean('Sale Order Layout Improvement',
+ help="This module provides some features to improve the layout of the Sale Order."),
+ 'sale_margin': fields.boolean('Margins in Sale Orders',
+ help="This module adds the 'Margin' on sales order, "
+ "which gives the profitability by calculating "
+ "the difference between the Unit Price and Cost Price."),
+ 'sale_order_dates': fields.boolean('Sale Order Dates',
+ help="Add commitment, requested and effective dates on the sale order."),
+ }
+sale_installer()
diff --git a/addons/sale/sale_installer.xml b/addons/sale/sale_installer.xml
new file mode 100644
index 00000000000..c77faf905e6
--- /dev/null
+++ b/addons/sale/sale_installer.xml
@@ -0,0 +1,66 @@
+
+
+
+ sale.installer.view
+ sale.installer
+ form
+
+
+
+
+ Sale Management Modules Installation
+
+
+
+ Sales Management
+
+
+ After having installed the core sales application, you can extend it depending on the needs of your sale's organization.
+
+
+
+
+
+ Configure
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Sale Management Modules Installation
+ ir.actions.act_window
+ sale.installer
+
+ form
+ form
+ new
+
+
+
+
+ 3
+
+
+
+
+ ir.actions.todo
+ sale_installer_action_replace
+ tree
+
+
+
+
+
+
+
+
+
diff --git a/addons/sale/sale_view.xml b/addons/sale/sale_view.xml
index ce39930f039..8cb74fb95c5 100644
--- a/addons/sale/sale_view.xml
+++ b/addons/sale/sale_view.xml
@@ -79,11 +79,11 @@
tree
-
-
+
+
@@ -163,12 +163,14 @@
+
+
@@ -280,8 +282,9 @@
-
+
+
diff --git a/addons/sale/test/advance_invoice.yml b/addons/sale/test/advance_invoice.yml
index 8b93b031d39..5a8d06c354c 100644
--- a/addons/sale/test/advance_invoice.yml
+++ b/addons/sale/test/advance_invoice.yml
@@ -1,269 +1,23 @@
-
- In order to test the sale module in the Open-ERP, I need to configure details regarding product & customer.
--
- I am going to sell my Mobile products to the customer with name Cleartrail
+ In order to test the Deposit wizard of sale module in the Open-ERP,
+ I create a Sale Order for LG Viewty Smart for qty 100 having order_policy manual.
-
- I create View Account Type.
--
- !record {model: account.account.type, id: account_account_type_view0}:
- close_method: none
- code: View
- name: View
- sign: 1
--
- I create Income Account Type.
--
- !record {model: account.account.type, id: account_account_type_income0}:
- close_method: unreconciled
- code: Income
- name: Income
- sign: 1
--
- I create Expense Account Type.
--
- !record {model: account.account.type, id: account_account_type_expense0}:
- close_method: unreconciled
- code: Expense
- name: Expense
- sign: 1
--
- I create Cash Account Type.
--
- !record {model: account.account.type, id: account_account_type_cash0}:
- close_method: balance
- code: Cash
- name: Cash
- sign: 1
--
- I create Minimal Chart Account.
--
- !record {model: account.account, id: account_account_minimalchart0}:
- code: '0'
- company_id: base.main_company
- currency_mode: current
- name: Minimal Chart
- parent_left: 1
- parent_right: 12
- type: view
- user_type: account_account_type_view0
--
- I create Payable Account.
--
- !record {model: account.account, id: account_account_payable1}:
- code: AP
- company_id: base.main_company
- currency_mode: current
- name: Payable
- parent_id: account_account_minimalchart0
- parent_left: 2
- parent_right: 3
- reconcile: true
- type: payable
- user_type: account_account_type_expense0
--
- I create Receivable Account.
--
- !record {model: account.account, id: account_account_receivable0}:
- code: AR
- currency_mode: current
- name: Receivable
- parent_id: account_account_minimalchart0
- parent_left: 4
- parent_right: 5
- reconcile: true
- type: receivable
- user_type: account_account_type_income0
--
- I create Cash Account.
--
- !record {model: account.account, id: account_account_cash0}:
- code: C
- currency_mode: current
- name: Cash
- parent_id: account_account_minimalchart0
- parent_left: 6
- parent_right: 7
- type: other
- user_type: account_account_type_cash0
--
- I create Purchases Account.
--
- !record {model: account.account, id: account_account_purchases0}:
- code: P
- company_id: base.main_company
- currency_mode: current
- name: Purchases
- parent_id: account_account_minimalchart0
- parent_left: 8
- parent_right: 9
- type: other
- user_type: account_account_type_expense0
--
- I create Sales Account.
--
- !record {model: account.account, id: account_account_sales0}:
- code: S
- company_id: base.main_company
- currency_mode: current
- name: Sales
- parent_id: account_account_minimalchart0
- parent_left: 10
- parent_right: 11
- type: other
- user_type: account_account_type_income0
--
- I create Purchase Journal.
--
- !record {model: account.journal, id: account_journal_purchasejournal0}:
- code: PUJ
- company_id: base.main_company
- default_credit_account_id: account_account_purchases0
- default_debit_account_id: account_account_purchases0
- name: Purchase Journal
- sequence_id: account.sequence_purchase_journal
- type: purchase
- view_id: account.account_journal_view
--
- I create Sale Journal.
--
- !record {model: account.journal, id: account_journal_salejournal0}:
- code: SAJ
- company_id: base.main_company
- default_credit_account_id: account_account_sales0
- default_debit_account_id: account_account_sales0
- name: Sale Journal
- sequence_id: account.sequence_sale_journal
- type: sale
- view_id: account.account_journal_view
--
- I create Bank Journal.
--
- !record {model: account.journal, id: account_journal_bankjournal0}:
- code: BNK
- default_credit_account_id: account_account_cash0
- default_debit_account_id: account_account_cash0
- name: Bank Journal
- sequence_id: account.sequence_journal
- type: cash
- view_id: account.account_journal_bank_view
--
- I create ir.property for account payable.
--
- !record {model: ir.property, id: ir_property_propertyaccountexpensecateg0}:
- company_id: base.main_company
- fields_id: account.field_res_partner_property_account_payable
- name: property_account_expense_categ
- value_reference: account.account,5
--
- I create ir.property for account receivable.
--
- !record {model: ir.property, id: ir_property_propertyaccountincomecateg0}:
- company_id: base.main_company
- fields_id: account.field_res_partner_property_account_receivable
- name: property_account_income_categ
- value_reference: account.account,6
--
- I create Partner category Customers.
--
- !record {model: res.partner.category, id: res_partner_category_customers0}:
- name: Customers
--
- I create Cleartrail Customer.
--
- !record {model: res.partner, id: res_partner_cleartrail0}:
- category_id:
- - res_partner_category_customers0
- name: Cleartrail
--
- I create contact address for Cleartrail.
--
- !record {model: res.partner.address, id: res_partner_address_1}:
- partner_id: res_partner_cleartrail0
- street: onam plaza, 14 B palasia A B Road
- type: contact
--
- I create invoice address for Cleartrail.
--
- !record {model: res.partner.address, id: res_partner_address_2}:
- partner_id: res_partner_cleartrail0
- street: sarda house 24 B palasia, A B Road
- type: invoice
--
- I create delivery address for Cleartrail.
--
- !record {model: res.partner.address, id: res_partner_address_3}:
- partner_id: res_partner_cleartrail0
- street: sangam house 15 B palasia, A B Road
- type: delivery
--
- Customer Cleartrail has specific instrument requirement regarding the stockable products.
--
- I define product category Mobile Products Sellable.
--
- !record {model: product.category, id: product_category_allproductssellable0}:
- name: Mobile Products Sellable
-
-
--
- I define product category Mobile Services.
--
- !record {model: product.category, id: product_category_services0}:
- name: Mobile Services
--
- I define LG Viewty Smart product template.
--
- !record {model: product.template, id: product_template_lgviewtysmart0}:
- categ_id: product_category_allproductssellable0
- cost_method: standard
- list_price: 170.0
- mes_type: fixed
- name: LG Viewty Smart
- procure_method: make_to_order
- standard_price: 160.0
- supply_method: produce
- type: product
- uom_id: product.product_uom_unit
- uom_po_id: product.product_uom_unit
-
--
- I define LG Viewty Smart product.
--
- !record {model: product.product, id: product_product_lgviewtysmart0}:
- categ_id: product_category_allproductssellable0
- cost_method: standard
- list_price: 170.0
- mes_type: fixed
- name: LG Viewty Smart
- pricelist_purchase: 'Default Purchase Pricelist (0.00) : 160.00\n'
- pricelist_sale: 'Public Pricelist (0.00) : 170.00\n'
- procure_method: make_to_order
- property_account_expense: sale.account_account_payable1
- property_account_income: sale.account_account_receivable0
- seller_delay: '1'
- standard_price: 160.0
- supply_method: produce
- type: product
- uom_id: product.product_uom_unit
- uom_po_id: product.product_uom_unit
--
- I create a Sale Order for LG Viewty Smart for qty 500 having order_policy prepaid.
--
- !record {model: sale.order, id: sale_order_so0}:
- date_order: '2010-05-03'
+ !record {model: sale.order, id: sale_order_so5}:
+ date_order: '2010-07-17'
invoice_quantity: order
name: SO004
order_line:
- name: LG Viewty Smart
price_unit: 170.0
product_uom: product.product_uom_unit
- product_uom_qty: 500.0
+ product_uom_qty: 100.0
state: draft
delay: 7.0
product_id: sale.product_product_lgviewtysmart0
- product_uos_qty: 500.0
+ product_uos_qty: 100.0
th_weight: 0.0
type: make_to_order
- order_policy: prepaid
+ order_policy: manual
partner_id: sale.res_partner_cleartrail0
partner_invoice_id: sale.res_partner_address_2
partner_order_id: sale.res_partner_address_1
@@ -271,28 +25,164 @@
picking_policy: direct
pricelist_id: product.list0
shop_id: sale.shop
-
+-
+ I confirm the Sale Order.
-
- I use the Advance Payment wizard.
+ !workflow {model: sale.order, action: order_confirm, ref: sale_order_so5}
+-
+ I use the Advance Payment wizard.
-
!record {model: sale.advance.payment.inv, id: sale_advance_payment_inv_0}:
amount: 1000.0
product_id: product.product_product_pc3
qtty: 3.0
-
-
-
- Performing an osv_memory action create_invoices on module sale.advance.payment.inv
+ Then I click on the "Create Partial Invoice" button
-
!python {model: sale.advance.payment.inv}: |
self.create_invoices(cr, uid, [ref("sale_advance_payment_inv_0")], {"lang": 'en_US',
- "active_model": 'sale.order', "active_ids": [ref("sale_order_so0")], "tz":
- False, "active_id": ref("sale_order_so0"), })
+ "active_model": 'sale.order', "active_ids": [ref("sale_order_so5")], "tz":
+ False, "active_id": ref("sale_order_so5"), })
-
- I will verify whether the invoice has been generated.
+ I verify whether the invoice has been generated.
-
!python {model: sale.order}: |
- so = self.browse(cr, uid, ref("sale_order_so0"))
- assert so.invoice_ids, "Invoices has not been generated for sale_order_so0"
-
-
+ so = self.browse(cr, uid, ref("sale_order_so5"))
+ assert so.invoice_ids, "Invoices has not been generated for sale_order_so5"
+-
+ I open the Invoice for the SO.
+-
+ !python {model: account.invoice}: |
+ sale_order_obj = self.pool.get('sale.order')
+ so = sale_order_obj.browse(cr, uid, ref("sale_order_so5"))
+ import netsvc
+ wf_service = netsvc.LocalService("workflow")
+ invoice_ids = so.invoice_ids
+ for invoice in invoice_ids:
+ wf_service.trg_validate(uid, 'account.invoice',invoice.id,'invoice_open', cr)
+-
+ I verify that an invoice state has transit from draft to open state
+-
+ !python {model: account.invoice}: |
+ sale_order_obj = self.pool.get('sale.order')
+ so = sale_order_obj.browse(cr, uid, ref("sale_order_so5"))
+ invoice_id = self.search(cr, uid, [('origin','=',so.name) and ('state','=','open')])
+ assert invoice_id, "Invoice is not in the open state"
+-
+ Creating a account invoice pay entry.
+-
+ !record {model: account.invoice.pay, id: account_invoice_pay_tst0}:
+ amount: 3000.0
+ date: '2010-07-17'
+ journal_id: sale.account_journal_bankjournal0
+ name: test
+ period_id: account.period_5
+-
+ I pay the invoice.
+-
+ !python {model: account.invoice.pay}: |
+ sale_order_obj = self.pool.get('sale.order')
+ so = sale_order_obj.browse(cr, uid, ref("sale_order_so5"))
+ self.wo_check(cr, uid, [ref("account_invoice_pay_tst0")], {"lang": "en_US", "active_model": "account.invoice",
+ "tz":False,"record_id": so.invoice_ids[0].id, "active_ids": [so.invoice_ids[0].id], "type":
+ "out_invoice", "active_id": so.invoice_ids[0].id})
+-
+ Creating an account invoice pay writeoff entry.
+-
+ !record {model: account.invoice.pay.writeoff, id: account_invoice_pay_writeoff_5}:
+ analytic_id: account.analytic_customers
+ comment: Write-Off
+ writeoff_acc_id: account.a_sale
+ writeoff_journal_id: sale.account_journal_bankjournal0
+-
+ I verify that invoice has transit from Open to Done state
+-
+ !python {model: account.invoice}: |
+ sale_order_obj = self.pool.get('sale.order')
+ so = sale_order_obj.browse(cr, uid, ref("sale_order_so5"))
+ invoice_id = self.search(cr, uid, [('origin','=',so.name) and ('state','=','paid')])
+ assert invoice_id, "Invoice for SO is not in done state."
+-
+ I verify that Paid has been set to true.
+-
+ !python {model: sale.order}: |
+ sale_id=self.browse(cr, uid, ref("sale_order_so5"))
+ assert(sale_id.invoiced == True), "Paid has not been set to true"
+-
+ I click on "Create Invoice" button of Sales order to create the invoice.
+-
+ !workflow {model: sale.order, action: manual_invoice, ref: sale_order_so5}
+-
+ I verify whether the invoice has been generated for SO
+-
+ !python {model: sale.order}: |
+ so = self.browse(cr, uid, ref("sale_order_so5"))
+ assert so.invoice_ids[1], "Invoices has not been generated for sale_order_so5"
+-
+ I open the Invoice for the SO.
+-
+ !python {model: account.invoice}: |
+ sale_order_obj = self.pool.get('sale.order')
+ so = sale_order_obj.browse(cr, uid, ref("sale_order_so5"))
+ import netsvc
+ wf_service = netsvc.LocalService("workflow")
+ invoice_ids = so.invoice_ids
+ for invoice in invoice_ids:
+ wf_service.trg_validate(uid, 'account.invoice',invoice.id,'invoice_open', cr)
+-
+ I verify that an invoice state has transit from draft to open state
+-
+ !python {model: account.invoice}: |
+ sale_order_obj = self.pool.get('sale.order')
+ so = sale_order_obj.browse(cr, uid, ref("sale_order_so5"))
+ invoice_id = self.search(cr, uid, [('origin','=',so.name) and ('state','=','open')])
+ assert invoice_id, "Invoice is not in the open state"
+-
+ Creating a account invoice pay entry.
+-
+ !record {model: account.invoice.pay, id: account_invoice_pay_tst2}:
+ amount: 14000.0
+ date: '2010-07-17'
+ journal_id: sale.account_journal_bankjournal0
+ name: test
+ period_id: account.period_5
+-
+ I pay the invoice.
+-
+ !python {model: account.invoice.pay}: |
+ sale_order_obj = self.pool.get('sale.order')
+ so = sale_order_obj.browse(cr, uid, ref("sale_order_so5"))
+ self.wo_check(cr, uid, [ref("account_invoice_pay_tst2")], {"lang": "en_US", "active_model": "account.invoice",
+ "tz":False,"record_id": so.invoice_ids[1].id, "active_ids": [so.invoice_ids[1].id], "type":
+ "out_invoice", "active_id": so.invoice_ids[1].id})
+-
+ Creating an account invoice pay writeoff entry.
+-
+ !record {model: account.invoice.pay.writeoff, id: account_invoice_pay_writeoff_0}:
+ analytic_id: account.analytic_customers
+ comment: Write-Off
+ writeoff_acc_id: account.a_sale
+ writeoff_journal_id: sale.account_journal_bankjournal0
+-
+ Pay and Reconcile the Invoice.
+-
+ !python {model: account.invoice.pay.writeoff}: |
+ sale_order_obj = self.pool.get('sale.order')
+ so = sale_order_obj.browse(cr, uid, ref("sale_order_so5"))
+ self.pay_and_reconcile_writeoff(cr, uid, [ref("account_invoice_pay_writeoff_0")],
+ {"lang": 'en_US', "tz": False, "active_model": 'account.invoice', "active_ids":
+ [so.invoice_ids[1].id], "type": "out_invoice", "active_id": so.invoice_ids[1].id})
+-
+ I verify that an invoice is in done state.
+-
+ !python {model: account.invoice}: |
+ sale_order_obj = self.pool.get('sale.order')
+ so = sale_order_obj.browse(cr, uid, ref("sale_order_so5"))
+ invoice_id = self.search(cr, uid, [('origin','=',so.name) and ('state','=','paid')])
+ assert invoice_id, "Invoice for SO is not in done state."
+-
+ I verify that Paid has been set to true.
+-
+ !python {model: sale.order}: |
+ sale_id=self.browse(cr, uid, ref("sale_order_so5"))
+ assert(sale_id.invoiced == True), "Paid has not been set to true"
\ No newline at end of file
diff --git a/addons/sale/test/prepaid_sale_order.yml b/addons/sale/test/data_test.yml
similarity index 58%
rename from addons/sale/test/prepaid_sale_order.yml
rename to addons/sale/test/data_test.yml
index ce344bb23ae..ef3b0bfe0ed 100644
--- a/addons/sale/test/prepaid_sale_order.yml
+++ b/addons/sale/test/data_test.yml
@@ -1,42 +1,42 @@
-
- In order to test the sale module in the Open-ERP, I need to configure details regarding product & customer.
+ In order to test the sale module, I need to configure details regarding product,customer and account.
-
I am going to sell my Mobile products to the customer with name Cleartrail
--
+-
I create View Account Type.
--
+-
!record {model: account.account.type, id: account_account_type_view0}:
close_method: none
code: View
name: View
sign: 1
--
+-
I create Income Account Type.
--
+-
!record {model: account.account.type, id: account_account_type_income0}:
close_method: unreconciled
code: Income
name: Income
sign: 1
--
+-
I create Expense Account Type.
--
+-
!record {model: account.account.type, id: account_account_type_expense0}:
close_method: unreconciled
code: Expense
name: Expense
sign: 1
--
+-
I create Cash Account Type.
--
+-
!record {model: account.account.type, id: account_account_type_cash0}:
close_method: balance
code: Cash
name: Cash
sign: 1
--
+-
I create Minimal Chart Account.
--
+-
!record {model: account.account, id: account_account_minimalchart0}:
code: '0'
company_id: base.main_company
@@ -46,9 +46,9 @@
parent_right: 12
type: view
user_type: account_account_type_view0
--
+-
I create Payable Account.
--
+-
!record {model: account.account, id: account_account_payable1}:
code: AP
company_id: base.main_company
@@ -60,11 +60,12 @@
reconcile: true
type: payable
user_type: account_account_type_expense0
--
+-
I create Receivable Account.
--
+-
!record {model: account.account, id: account_account_receivable0}:
code: AR
+ company_id: base.main_company
currency_mode: current
name: Receivable
parent_id: account_account_minimalchart0
@@ -73,11 +74,12 @@
reconcile: true
type: receivable
user_type: account_account_type_income0
--
+-
I create Cash Account.
--
+-
!record {model: account.account, id: account_account_cash0}:
code: C
+ company_id: base.main_company
currency_mode: current
name: Cash
parent_id: account_account_minimalchart0
@@ -85,9 +87,9 @@
parent_right: 7
type: other
user_type: account_account_type_cash0
--
+-
I create Purchases Account.
--
+-
!record {model: account.account, id: account_account_purchases0}:
code: P
company_id: base.main_company
@@ -98,9 +100,9 @@
parent_right: 9
type: other
user_type: account_account_type_expense0
--
+-
I create Sales Account.
--
+-
!record {model: account.account, id: account_account_sales0}:
code: S
company_id: base.main_company
@@ -111,9 +113,9 @@
parent_right: 11
type: other
user_type: account_account_type_income0
--
+-
I create Purchase Journal.
--
+-
!record {model: account.journal, id: account_journal_purchasejournal0}:
code: PUJ
company_id: base.main_company
@@ -123,9 +125,9 @@
sequence_id: account.sequence_purchase_journal
type: purchase
view_id: account.account_journal_view
--
+-
I create Sale Journal.
--
+-
!record {model: account.journal, id: account_journal_salejournal0}:
code: SAJ
company_id: base.main_company
@@ -135,81 +137,80 @@
sequence_id: account.sequence_sale_journal
type: sale
view_id: account.account_journal_view
--
+-
I create Bank Journal.
--
+-
!record {model: account.journal, id: account_journal_bankjournal0}:
code: BNK
+ company_id: base.main_company
default_credit_account_id: account_account_cash0
default_debit_account_id: account_account_cash0
name: Bank Journal
sequence_id: account.sequence_journal
type: cash
view_id: account.account_journal_bank_view
--
+-
I create ir.property for account payable.
--
+-
!record {model: ir.property, id: ir_property_propertyaccountexpensecateg0}:
company_id: base.main_company
fields_id: account.field_res_partner_property_account_payable
name: property_account_expense_categ
value_reference: account.account,5
--
+-
I create ir.property for account receivable.
--
+-
!record {model: ir.property, id: ir_property_propertyaccountincomecateg0}:
company_id: base.main_company
fields_id: account.field_res_partner_property_account_receivable
name: property_account_income_categ
value_reference: account.account,6
--
+-
I create Partner category Customers.
--
+-
!record {model: res.partner.category, id: res_partner_category_customers0}:
name: Customers
-
I create Cleartrail Customer.
--
+-
!record {model: res.partner, id: res_partner_cleartrail0}:
category_id:
- res_partner_category_customers0
name: Cleartrail
--
+-
I create contact address for Cleartrail.
--
+-
!record {model: res.partner.address, id: res_partner_address_1}:
partner_id: res_partner_cleartrail0
street: onam plaza, 14 B palasia A B Road
type: contact
--
+-
I create invoice address for Cleartrail.
--
+-
!record {model: res.partner.address, id: res_partner_address_2}:
partner_id: res_partner_cleartrail0
street: sarda house 24 B palasia, A B Road
type: invoice
--
+-
I create delivery address for Cleartrail.
--
+-
!record {model: res.partner.address, id: res_partner_address_3}:
partner_id: res_partner_cleartrail0
street: sangam house 15 B palasia, A B Road
type: delivery
-
Customer Cleartrail has specific instrument requirement regarding the stockable products.
--
+-
I define product category Mobile Products Sellable.
--
+-
!record {model: product.category, id: product_category_allproductssellable0}:
name: Mobile Products Sellable
-
-
--
- I define product category Mobile Services.
-
+ I define product category Mobile Services.
+-
!record {model: product.category, id: product_category_services0}:
name: Mobile Services
--
+-
I define LG Viewty Smart product template.
-
!record {model: product.template, id: product_template_lgviewtysmart0}:
@@ -239,138 +240,53 @@
property_account_expense: sale.account_account_payable1
property_account_income: sale.account_account_receivable0
seller_delay: '1'
+ seller_ids:
+ - delay: 1
+ name: base.res_partner_agrolait
+ min_qty: 2.0
+ qty: 5.0
standard_price: 160.0
supply_method: produce
type: product
uom_id: product.product_uom_unit
uom_po_id: product.product_uom_unit
-
- I create a Sale Order for LG Viewty Smart for qty 500 having order_policy prepaid.
--
- !record {model: sale.order, id: sale_order_so1}:
- date_order: '2010-05-03'
- invoice_quantity: order
- name: Test_SO001
- order_line:
- - name: LG Viewty Smart
- price_unit: 170.0
- product_uom: product.product_uom_unit
- product_uom_qty: 500.0
- state: draft
- delay: 7.0
- product_id: sale.product_product_lgviewtysmart0
- product_uos_qty: 500.0
- th_weight: 0.0
- type: make_to_order
- order_policy: prepaid
- partner_id: sale.res_partner_cleartrail0
- partner_invoice_id: sale.res_partner_address_2
- partner_order_id: sale.res_partner_address_1
- partner_shipping_id: sale.res_partner_address_3
- picking_policy: direct
- pricelist_id: product.list0
- shop_id: sale.shop
-
-
--
- I confirm the sale order.
--
- !workflow {model: sale.order, action: order_confirm, ref: sale_order_so1}
--
- I will verify whether the invoice has been generated for SO since Shipping policy is 'Payment Before Delivery'
--
- !python {model: sale.order}: |
- so = self.browse(cr, uid, ref("sale_order_so1"))
- assert so.invoice_ids, "Invoices has not been generated for sale_order_so1"
--
- I open the Invoice for the SO.
--
- !python {model: account.invoice}: |
- sale_order_obj = self.pool.get('sale.order')
- so = sale_order_obj.browse(cr, uid, ref("sale_order_so1"))
- import netsvc
- wf_service = netsvc.LocalService("workflow")
- invoice_ids = so.invoice_ids
- for invoice in invoice_ids:
- wf_service.trg_validate(uid, 'account.invoice',invoice.id,'invoice_open', cr)
--
- Creating a account invoice pay entry.
--
- !record {model: account.invoice.pay, id: account_invoice_pay_tst1}:
- amount: 85000.0
- date: '2010-05-10'
- journal_id: sale.account_journal_bankjournal0
- name: tst
- period_id: account.period_5
--
- I pay the invoice.
--
- !python {model: account.invoice.pay}: |
- sale_order_obj = self.pool.get('sale.order')
- so = sale_order_obj.browse(cr, uid, ref("sale_order_so1"))
- self.wo_check(cr, uid, [ref("account_invoice_pay_tst1")], {"lang": "en_US", "tz":
- False, "active_model": 'account.invoice', "active_ids": [so.invoice_ids[0].id], "type":
- "out_invoice", "active_id": so.invoice_ids[0].id, })
-
-
--
- Creating an account invoice pay writeoff entry.
--
- !record {model: account.invoice.pay.writeoff, id: account_invoice_pay_writeoff_0}:
- analytic_id: account.analytic_customers
- comment: Write-Off
- writeoff_acc_id: account.a_sale
- writeoff_journal_id: sale.account_journal_bankjournal0
-
-
--
- Pay and Reconcile the Invoice.
--
- !python {model: account.invoice.pay.writeoff}: |
- sale_order_obj = self.pool.get('sale.order')
- so = sale_order_obj.browse(cr, uid, ref("sale_order_so1"))
- self.pay_and_reconcile_writeoff(cr, uid, [ref("account_invoice_pay_writeoff_0")],
- {"lang": 'en_US', "tz": False, "active_model": 'account.invoice', "active_ids":
- [so.invoice_ids[0].id], "type": "out_invoice", "active_id": so.invoice_ids[0].id })
-
-
--
- I will verify the picking associated with the sale order sale_order_so1
--
- !python {model: sale.order}: |
- so = self.browse(cr, uid, ref("sale_order_so1"))
- assert so.picking_ids,"Picking has not been generated for sale_order_so1"
--
- Products are delivered to the Cleartrail Customer.
--
- !python {model: stock.picking }: |
- import time
- sale_order_obj = self.pool.get('sale.order')
- so = sale_order_obj.browse(cr, uid, ref("sale_order_so1"))
- picking_id = self.search(cr, uid, [('origin','=',so.name),('type','=','out')])
- if picking_id:
- pick=self.browse(cr,uid,picking_id[0])
- pick.force_assign(cr, uid)
- partial_datas = {
- 'partner_id':pick.address_id.partner_id.id,
- 'address_id': pick.address_id.id,
- 'delivery_date' : time.strftime('%Y-%m-%d'),
- }
- move = pick.move_lines[0]
- partial_datas['move%s'%(move.id)]= {
- 'product_id': move.product_id.id,
- 'product_qty': move.product_qty,
- 'product_uom': move.product_uom.id,
- }
- self.do_partial(cr, uid, [pick.id],partial_datas)
--
- I verify that picking order is in done state.
--
- !python {model: stock.picking }: |
- sale_order_obj = self.pool.get('sale.order')
- so = sale_order_obj.browse(cr, uid, ref("sale_order_so1"))
- picking_id = self.search(cr, uid, [('origin','=',so.name),('type','=','out')])
-
- if picking_id:
- pick = self.browse(cr,uid,picking_id[0])
- assert (pick.state) =='done', "Picking for SO is not in done state."
+ I define Slider Mobile template.
+-
+ !record {model: product.template, id: product_template_slidermobile0}:
+ categ_id: product_category_allproductssellable0
+ cost_method: standard
+ list_price: 200.0
+ mes_type: fixed
+ name: Slider Mobile
+ procure_method: make_to_order
+ standard_price: 189.0
+ supply_method: buy
+ type: product
+ uom_id: product.product_uom_unit
+ uom_po_id: product.product_uom_unit
+-
+ I define Slider Mobile.
+-
+ !record {model: product.product, id: product_product_slidermobile0}:
+ categ_id: product_category_allproductssellable0
+ cost_method: standard
+ list_price: 200
+ mes_type: fixed
+ name: Slider Mobile
+ pricelist_purchase: 'Default Purchase Pricelist (0.00) : 500.0.00\n'
+ pricelist_sale: 'Public Pricelist (0.00) : 510.00\n'
+ procure_method: make_to_order
+ property_account_expense: sale.account_account_payable1
+ property_account_income: sale.account_account_receivable0
+ seller_delay: '1'
+ seller_ids:
+ - delay: 1
+ name: base.res_partner_agrolait
+ min_qty: 2.0
+ qty: 5.0
+ standard_price: 189.0
+ supply_method: buy
+ type: product
+ uom_id: product.product_uom_unit
+ uom_po_id: product.product_uom_unit
diff --git a/addons/sale/test/invoice_on_ordered_qty.yml b/addons/sale/test/invoice_on_ordered_qty.yml
new file mode 100644
index 00000000000..9056e4cbb83
--- /dev/null
+++ b/addons/sale/test/invoice_on_ordered_qty.yml
@@ -0,0 +1,151 @@
+-
+ In order to test the Sale module in OpenERP,
+ I create a Sale Order for Slider Mobile for 500 quantity having Shipping Policy 'Shipping & Manual Invoice' and Invoice on 'Ordered quantities'
+ in order to create an invoice based on the ordered quantity
+-
+ !record {model: sale.order, id: sale_order_so8}:
+ date_order: '2010-07-17'
+ invoice_quantity: order
+ name: Test_SO006
+ order_line:
+ - name: Slider Mobile
+ price_unit: 200
+ product_uom: product.product_uom_unit
+ product_uom_qty: 200.0
+ state: draft
+ delay: 7.0
+ product_id: sale.product_product_slidermobile0
+ product_uos_qty: 200.0
+ type: make_to_order
+ order_policy: manual
+ invoice_quantity: order
+ partner_id: sale.res_partner_cleartrail0
+ partner_invoice_id: sale.res_partner_address_2
+ partner_order_id: sale.res_partner_address_1
+ partner_shipping_id: sale.res_partner_address_3
+ picking_policy: direct
+ pricelist_id: product.list0
+ shop_id: sale.shop
+-
+ I confirm the Sale Order.
+-
+ !workflow {model: sale.order, action: order_confirm, ref: sale_order_so8}
+-
+ I verify that the picking has been generated for the sale order
+-
+ !python {model: sale.order}: |
+ so = self.browse(cr, uid, ref("sale_order_so8"))
+ assert so.picking_ids,"Picking has not been generated for sale_order_so8"
+-
+ Then I click on the "Products Received" button of Incoming Shipments
+-
+ !record {model: stock.partial.picking, id: stock_partial_picking_0}:
+ date: '2010-07-17 17:52:09'
+-
+ Then I done the picking
+-
+ !python {model: stock.picking }: |
+ import time
+ sale_order_obj = self.pool.get('sale.order')
+ so = sale_order_obj.browse(cr, uid, ref("sale_order_so8"))
+ picking_id = self.search(cr, uid, [('origin','=',so.name),('type','=','out')])
+ if picking_id:
+ pick=self.browse(cr,uid,picking_id[0])
+ pick.force_assign(cr, uid)
+ partial_datas = {
+ 'partner_id':pick.address_id.partner_id.id,
+ 'address_id': pick.address_id.id,
+ 'delivery_date' : time.strftime('%Y-%m-%d'),
+ }
+ move = pick.move_lines[0]
+ partial_datas['move%s'%(move.id)]= {
+ 'product_id': move.product_id.id,
+ 'product_qty': '100',
+ 'product_uom': move.product_uom.id,
+ }
+ self.do_partial(cr, uid, [pick.id],partial_datas)
+-
+ I click on Create Invoice button to create the invoice.
+-
+ !workflow {model: sale.order, action: manual_invoice, ref: sale_order_so8}
+-
+ I verify whether the invoice has been generated for SO
+-
+ !python {model: sale.order}: |
+ so = self.browse(cr, uid, ref("sale_order_so8"))
+ assert so.invoice_ids, "Invoices has not been generated for sale_order_so8"
+-
+ I verify that an invoice is created on the basis of ordered quantity
+-
+ !python {model: account.invoice}: |
+ sale_order_obj = self.pool.get('sale.order')
+ so = sale_order_obj.browse(cr, uid, ref("sale_order_so8"))
+ for so_lines in so.order_line:
+ qty=so_lines.product_uom_qty
+ ids = self.search(cr, uid, [('origin', '=', so.name)])
+ inv_brw = self.browse(cr,uid,ids)[0]
+ for inv_lines in inv_brw.invoice_line:
+ qty1=inv_lines.quantity
+ invoice_id = self.search(cr, uid, [('qty1','=', 'qty') and ('origin', '=', so.name)])
+ assert invoice_id, "Quantities are not same"
+-
+ I open the Invoice for the SO.
+-
+ !python {model: account.invoice}: |
+ sale_order_obj = self.pool.get('sale.order')
+ so = sale_order_obj.browse(cr, uid, ref("sale_order_so8"))
+ import netsvc
+ wf_service = netsvc.LocalService("workflow")
+ invoice_ids = so.invoice_ids
+ for invoice in invoice_ids:
+ wf_service.trg_validate(uid, 'account.invoice',invoice.id,'invoice_open', cr)
+-
+ Creating a account invoice pay entry.
+-
+ !record {model: account.invoice.pay, id: account_invoice_pay_tst1}:
+ amount: 40000.0
+ date: '2010-07-17'
+ journal_id: sale.account_journal_bankjournal0
+ name: tst
+ period_id: account.period_5
+-
+ I pay the invoice.
+-
+ !python {model: account.invoice.pay}: |
+ sale_order_obj = self.pool.get('sale.order')
+ so = sale_order_obj.browse(cr, uid, ref("sale_order_so8"))
+ self.wo_check(cr, uid, [ref("account_invoice_pay_tst1")], {"lang": "en_US", "tz":
+ False, "active_model": 'account.invoice', "active_ids": [so.invoice_ids[0].id], "type":
+ "out_invoice", "active_id": so.invoice_ids[0].id, })
+-
+ Creating an account invoice pay writeoff entry.
+-
+ !record {model: account.invoice.pay.writeoff, id: account_invoice_pay_writeoff_0}:
+ analytic_id: account.analytic_customers
+ comment: Write-Off
+ writeoff_acc_id: account.a_sale
+ writeoff_journal_id: sale.account_journal_bankjournal0
+-
+ Pay and Reconcile the Invoice.
+-
+ !python {model: account.invoice.pay.writeoff}: |
+ sale_order_obj = self.pool.get('sale.order')
+ so = sale_order_obj.browse(cr, uid, ref("sale_order_so8"))
+ self.pay_and_reconcile_writeoff(cr, uid, [ref("account_invoice_pay_writeoff_0")],
+ {"lang": 'en_US', "tz": False, "active_model": 'account.invoice', "active_ids":
+ [so.invoice_ids[0].id], "type": "out_invoice", "active_id": so.invoice_ids[0].id })
+-
+ I verify the invoice are in paid state or not.
+-
+ !python {model: account.invoice}: |
+ sale_order_obj = self.pool.get('sale.order')
+ so = sale_order_obj.browse(cr, uid, ref("sale_order_so8"))
+ invoice_ids = so.invoice_ids
+ for invoice in invoice_ids:
+ assert (invoice.state) =='paid', "Invoice for SO is not in done state."
+-
+ I check that Paid has been set to true.
+-
+ !python {model: sale.order}: |
+ sale_id=self.browse(cr, uid, ref("sale_order_so8"))
+ assert(sale_id.invoiced == True), "Paid has not been set to true"
\ No newline at end of file
diff --git a/addons/sale/test/invoice_on_shipped_qty.yml b/addons/sale/test/invoice_on_shipped_qty.yml
new file mode 100644
index 00000000000..5a608aff9b8
--- /dev/null
+++ b/addons/sale/test/invoice_on_shipped_qty.yml
@@ -0,0 +1,154 @@
+-
+ In order to test the Sale module in OpenERP,
+ I create a Sale Order for Slider Mobile for 500 quantity having Shipping Policy 'Shipping & Manual Invoice' and Invoice on 'Shipped quantities'
+ in order to create an invoice based on the shipping quantity
+-
+ !record {model: sale.order, id: sale_order_so6}:
+ date_order: '2010-07-17'
+ invoice_quantity: order
+ name: Test_SO006
+ order_line:
+ - name: Slider Mobile
+ price_unit: 200
+ product_uom: product.product_uom_unit
+ product_uom_qty: 200.0
+ state: draft
+ delay: 7.0
+ product_id: sale.product_product_slidermobile0
+ product_uos_qty: 200.0
+ type: make_to_order
+ order_policy: manual
+ invoice_quantity: procurement
+ partner_id: sale.res_partner_cleartrail0
+ partner_invoice_id: sale.res_partner_address_2
+ partner_order_id: sale.res_partner_address_1
+ partner_shipping_id: sale.res_partner_address_3
+ picking_policy: direct
+ pricelist_id: product.list0
+ shop_id: sale.shop
+-
+ I confirm the Sale Order.
+-
+ !workflow {model: sale.order, action: order_confirm, ref: sale_order_so6}
+-
+ I verify that the picking has been generated for the sale order
+-
+ !python {model: sale.order}: |
+ so = self.browse(cr, uid, ref("sale_order_so6"))
+ assert so.picking_ids,"Picking has not been generated for sale_order_so6"
+-
+ Then I click on the "Products Received" button of Incoming Shipments
+-
+ !record {model: stock.partial.picking, id: stock_partial_picking_0}:
+ date: '2010-07-17 17:52:09'
+-
+ Then I done the picking
+-
+ !python {model: stock.picking }: |
+ import time
+ sale_order_obj = self.pool.get('sale.order')
+ so = sale_order_obj.browse(cr, uid, ref("sale_order_so6"))
+ picking_id = self.search(cr, uid, [('origin','=',so.name),('type','=','out')])
+ if picking_id:
+ pick=self.browse(cr,uid,picking_id[0])
+ pick.force_assign(cr, uid)
+ partial_datas = {
+ 'partner_id':pick.address_id.partner_id.id,
+ 'address_id': pick.address_id.id,
+ 'delivery_date' : time.strftime('%Y-%m-%d'),
+ }
+ move = pick.move_lines[0]
+ partial_datas['move%s'%(move.id)]= {
+ 'product_id': move.product_id.id,
+ 'product_qty': '100',
+ 'product_uom': move.product_uom.id,
+ }
+ self.do_partial(cr, uid, [pick.id],partial_datas)
+-
+ I click on Create Invoice button to create the invoice.
+-
+ !workflow {model: sale.order, action: manual_invoice, ref: sale_order_so6}
+-
+ I verify whether the invoice has been generated for SO
+-
+ !python {model: sale.order}: |
+ so = self.browse(cr, uid, ref("sale_order_so6"))
+ assert so.invoice_ids, "Invoices has not been generated for sale_order_so6"
+-
+ I verify that an invoice is created on the basis of shipped quantity
+-
+ !python {model: account.invoice}: |
+ sale_order_obj = self.pool.get('sale.order')
+ so = sale_order_obj.browse(cr, uid, ref("sale_order_so6"))
+ picking_obj = self.pool.get('stock.picking')
+ ids = picking_obj.search(cr, uid, [('origin', '=', so.name)])
+ pick_brw = picking_obj.browse(cr,uid, ids)[0]
+ for lines in pick_brw.move_lines:
+ qty=lines.product_qty
+ inv_id = self.search(cr, uid, [('origin', '=', so.name)])
+ inv_brw = self.browse(cr,uid,inv_id)[0]
+ for inv_lines in inv_brw.invoice_line:
+ qty1=inv_lines.quantity
+ invoice_id = self.search(cr, uid, [('qty1','=', 'qty') and ('origin', '=', so.name)])
+ assert invoice_id, "Quantities are not same"
+-
+ I open the Invoice for the SO.
+-
+ !python {model: account.invoice}: |
+ sale_order_obj = self.pool.get('sale.order')
+ so = sale_order_obj.browse(cr, uid, ref("sale_order_so6"))
+ import netsvc
+ wf_service = netsvc.LocalService("workflow")
+ invoice_ids = so.invoice_ids
+ for invoice in invoice_ids:
+ wf_service.trg_validate(uid, 'account.invoice',invoice.id,'invoice_open', cr)
+-
+ Creating a account invoice pay entry.
+-
+ !record {model: account.invoice.pay, id: account_invoice_pay_tst1}:
+ amount: 20000.0
+ date: '2010-07-17'
+ journal_id: sale.account_journal_bankjournal0
+ name: tst
+ period_id: account.period_5
+-
+ I pay the invoice.
+-
+ !python {model: account.invoice.pay}: |
+ sale_order_obj = self.pool.get('sale.order')
+ so = sale_order_obj.browse(cr, uid, ref("sale_order_so6"))
+ self.wo_check(cr, uid, [ref("account_invoice_pay_tst1")], {"lang": "en_US", "tz":
+ False, "active_model": 'account.invoice', "active_ids": [so.invoice_ids[0].id], "type":
+ "out_invoice", "active_id": so.invoice_ids[0].id, })
+-
+ Creating an account invoice pay writeoff entry.
+-
+ !record {model: account.invoice.pay.writeoff, id: account_invoice_pay_writeoff_0}:
+ analytic_id: account.analytic_customers
+ comment: Write-Off
+ writeoff_acc_id: account.a_sale
+ writeoff_journal_id: sale.account_journal_bankjournal0
+-
+ Pay and Reconcile the Invoice.
+-
+ !python {model: account.invoice.pay.writeoff}: |
+ sale_order_obj = self.pool.get('sale.order')
+ so = sale_order_obj.browse(cr, uid, ref("sale_order_so6"))
+ self.pay_and_reconcile_writeoff(cr, uid, [ref("account_invoice_pay_writeoff_0")],
+ {"lang": 'en_US', "tz": False, "active_model": 'account.invoice', "active_ids":
+ [so.invoice_ids[0].id], "type": "out_invoice", "active_id": so.invoice_ids[0].id })
+-
+ I verify the invoice are in paid state or not.
+-
+ !python {model: account.invoice}: |
+ sale_order_obj = self.pool.get('sale.order')
+ so = sale_order_obj.browse(cr, uid, ref("sale_order_so6"))
+ invoice_ids = so.invoice_ids
+ for invoice in invoice_ids:
+ assert (invoice.state) =='paid', "Invoice for SO is not in done state."
+-
+ I check that Paid has been set to true.
+-
+ !python {model: sale.order}: |
+ sale_id=self.browse(cr, uid, ref("sale_order_so6"))
+ assert(sale_id.invoiced == True), "Paid has not been set to true"
diff --git a/addons/sale/test/manual_order_policy.yml b/addons/sale/test/manual_order_policy.yml
new file mode 100644
index 00000000000..3d7abdcf549
--- /dev/null
+++ b/addons/sale/test/manual_order_policy.yml
@@ -0,0 +1,339 @@
+-
+ In order to test the Sale module in OpenERP,
+ I create a Sale Order for Slider Mobile for 500 quantity having Shipping Policy 'Shipping & Manual Invoice'
+-
+ !record {model: sale.order, id: sale_order_so0}:
+ date_order: '2010-07-17'
+ invoice_quantity: order
+ name: Test_SO002
+ order_line:
+ - name: Slider Mobile
+ price_unit: 200
+ product_uom: product.product_uom_unit
+ product_uom_qty: 500.0
+ state: draft
+ delay: 7.0
+ product_id: sale.product_product_slidermobile0
+ product_uos_qty: 500.0
+ type: make_to_order
+ order_policy: manual
+ partner_id: sale.res_partner_cleartrail0
+ partner_invoice_id: sale.res_partner_address_2
+ partner_order_id: sale.res_partner_address_1
+ partner_shipping_id: sale.res_partner_address_3
+ picking_policy: direct
+ pricelist_id: product.list0
+ shop_id: sale.shop
+-
+ I confirm the Sale Order.
+-
+ !workflow {model: sale.order, action: order_confirm, ref: sale_order_so0}
+-
+ I click on Create Invoice button to create the invoice.
+-
+ !workflow {model: sale.order, action: manual_invoice, ref: sale_order_so0}
+
+-
+ I verify whether the invoice has been generated for SO
+-
+ !python {model: sale.order}: |
+ so = self.browse(cr, uid, ref("sale_order_so0"))
+ assert so.invoice_ids, "Invoices has not been generated for sale_order_so0"
+-
+ I open the Invoice for the SO.
+-
+ !python {model: account.invoice}: |
+ sale_order_obj = self.pool.get('sale.order')
+ so = sale_order_obj.browse(cr, uid, ref("sale_order_so0"))
+ import netsvc
+ wf_service = netsvc.LocalService("workflow")
+ invoice_ids = so.invoice_ids
+ for invoice in invoice_ids:
+ wf_service.trg_validate(uid, 'account.invoice',invoice.id,'invoice_open', cr)
+-
+ I verify that an invoice state has transit from draft to open state
+-
+ !python {model: account.invoice}: |
+ sale_order_obj = self.pool.get('sale.order')
+ so = sale_order_obj.browse(cr, uid, ref("sale_order_so0"))
+ invoice_id = self.search(cr, uid, [('origin','=',so.name) and ('state','=','open')])
+ assert invoice_id, "Invoice is not in the open state"
+-
+ I verify that its Journal Entries has been created
+-
+ !python {model: account.invoice}: |
+ sale_order_obj = self.pool.get('sale.order')
+ so = sale_order_obj.browse(cr, uid, ref("sale_order_so0"))
+ invoice_id = self.search(cr, uid, [('origin','=',so.name) and ('state','=','open')])
+ inv_brw = self.browse(cr, uid, invoice_id)[0]
+ assert inv_brw.move_id, "Journal Entries has not been created"
+-
+ Creating a account invoice pay entry.
+-
+ !record {model: account.invoice.pay, id: account_invoice_pay_tst0}:
+ amount: 100000.0
+ date: '2010-07-17'
+ journal_id: sale.account_journal_bankjournal0
+ name: test
+ period_id: account.period_5
+-
+ I pay the invoice.
+-
+ !python {model: account.invoice.pay}: |
+ sale_order_obj = self.pool.get('sale.order')
+ so = sale_order_obj.browse(cr, uid, ref("sale_order_so0"))
+ self.wo_check(cr, uid, [ref("account_invoice_pay_tst0")], {"lang": "en_US", "active_model": "account.invoice",
+ "tz":False,"record_id": so.invoice_ids[0].id, "active_ids": [so.invoice_ids[0].id], "type":
+ "out_invoice", "active_id": so.invoice_ids[0].id})
+-
+ Creating an account invoice pay writeoff entry.
+-
+ !record {model: account.invoice.pay.writeoff, id: account_invoice_pay_writeoff_0}:
+ analytic_id: account.analytic_customers
+ comment: Write-Off
+ writeoff_acc_id: account.a_sale
+ writeoff_journal_id: sale.account_journal_bankjournal0
+-
+ Pay and Reconcile the Invoice.
+-
+ !python {model: account.invoice.pay.writeoff}: |
+ sale_order_obj = self.pool.get('sale.order')
+ so = sale_order_obj.browse(cr, uid, ref("sale_order_so0"))
+ self.pay_and_reconcile_writeoff(cr, uid, [ref("account_invoice_pay_writeoff_0")],
+ {"lang": 'en_US', "tz": False, "active_model": 'account.invoice', "active_ids":
+ [so.invoice_ids[0].id], "type": "out_invoice", "active_id": so.invoice_ids[0].id, })
+-
+ I verify the invoice is in done state.
+-
+ !python {model: account.invoice}: |
+ sale_order_obj = self.pool.get('sale.order')
+ so = sale_order_obj.browse(cr, uid, ref("sale_order_so0"))
+ invoice_id = self.search(cr, uid, [('origin','=',so.name) and ('state','=','paid')])
+ assert invoice_id, "Invoice for SO is not in done state."
+-
+ I verify that Paid has been set to true.
+-
+ !python {model: sale.order}: |
+ sale_id=self.browse(cr, uid, ref("sale_order_so0"))
+ assert(sale_id.invoiced == True), "Paid has not been set to true"
+-
+ I verify that the picking has been generated for the sale order
+-
+ !python {model: sale.order}: |
+ so = self.browse(cr, uid, ref("sale_order_so0"))
+ assert so.picking_ids,"Picking has not been generated for sale_order_so0"
+-
+ I verify that delivery order has been generated for sale order
+-
+ !python {model: stock.picking }: |
+ sale_order_obj = self.pool.get('sale.order')
+ so = sale_order_obj.browse(cr, uid, ref("sale_order_so0"))
+ picking_id = self.search(cr, uid, [('origin','=',so.name),('type','=','delivery')])
+ assert (picking_id),"Delivery order has not been generated"
+-
+ I verify that a procurement has been generated for so
+-
+ !python {model: procurement.order}: |
+ from tools.translate import _
+ sale_order_obj = self.pool.get('sale.order')
+ so = sale_order_obj.browse(cr, uid, ref("sale_order_so0"))
+ proc_ids = self.search(cr, uid, [('origin','=',so.name)])
+ assert proc_ids, _('No Procurements!')
+-
+ Then I click on the "Run Procurement" button
+-
+ !python {model: procurement.order}: |
+ sale_order_obj = self.pool.get('sale.order')
+ so = sale_order_obj.browse(cr, uid, ref("sale_order_so0"))
+ import netsvc
+ wf_service = netsvc.LocalService("workflow")
+ proc_ids = self.search(cr, uid, [('origin','=',so.name)])
+ for proc in proc_ids:
+ wf_service.trg_validate(uid, 'procurement.order',proc,'button_check', cr)
+-
+ I verify that a procurement state is "running"
+-
+ !python {model: procurement.order}: |
+ from tools.translate import _
+ modules = self.pool.get('ir.module.module')
+ mod_pur = modules.search(cr, uid, [('name','=','purchase')])
+ mod_brw = modules.browse(cr,uid,mod_pur)[0]
+ if (mod_brw.state == 'installed'):
+ sale_order_obj = self.pool.get('sale.order')
+ so = sale_order_obj.browse(cr, uid, ref("sale_order_so0"))
+ proc_ids = self.search(cr, uid, [('origin','=',so.name) and ('state','=','running')])
+ assert proc_ids, _('Procurement is not in the running state!')
+-
+ I verify that a purchase order has been generated
+-
+ !python {model: sale.order}: |
+ from tools.translate import _
+ modules = self.pool.get('ir.module.module')
+ mod_pur = modules.search(cr, uid, [('name','=','purchase')])
+ mod_brw = modules.browse(cr,uid,mod_pur)[0]
+ if(mod_brw.state == 'installed'):
+ so = self.browse(cr, uid, ref("sale_order_so0"))
+ pur_obj=self.pool.get('purchase.order')
+ pur_id=pur_obj.search(cr, uid, [('origin','=',so.name)])
+ assert pur_id, _('Purchase order has not been generated')
+
+-
+ I click on the "Confirm" button to confirm the purchase order
+-
+ !python {model: sale.order}: |
+ from tools.translate import _
+ modules = self.pool.get('ir.module.module')
+ mod_pur = modules.search(cr, uid, [('name','=','purchase')])
+ mod_brw = modules.browse(cr,uid,mod_pur)[0]
+ if(mod_brw.state == 'installed'):
+ pur_obj=self.pool.get('purchase.order')
+ so = self.browse(cr, uid, ref("sale_order_so0"))
+ import netsvc
+ wf_service = netsvc.LocalService("workflow")
+ pur_ids = pur_obj.search(cr, uid, [('origin','=',so.name)])
+ for pur in pur_ids:
+ wf_service.trg_validate(uid, 'purchase.order',pur,'purchase_confirm', cr)
+-
+ I click on the "Approved by supplier" button to approve the purchase order
+-
+ !python {model: sale.order}: |
+ from tools.translate import _
+ modules = self.pool.get('ir.module.module')
+ mod_pur = modules.search(cr, uid, [('name','=','purchase')])
+ mod_brw = modules.browse(cr,uid,mod_pur)[0]
+ if (mod_brw.state == 'installed'):
+ pur_obj = self.pool.get('purchase.order')
+ so = self.browse(cr, uid, ref("sale_order_so0"))
+ import netsvc
+ wf_service = netsvc.LocalService("workflow")
+ pur_ids = pur_obj.search(cr, uid, [('origin','=',so.name)])
+ for pur in pur_ids:
+ wf_service.trg_validate(uid, 'purchase.order',pur,'purchase_approve', cr)
+-
+ I verify that a picking related to purchase order has been generated.
+-
+ !python {model: sale.order}: |
+ modules = self.pool.get('ir.module.module')
+ mod_pur = modules.search(cr, uid, [('name','=','purchase')])
+ mod_brw = modules.browse(cr,uid,mod_pur)[0]
+ if (mod_brw.state == 'installed'):
+ pur_obj = self.pool.get('purchase.order')
+ so = self.browse(cr, uid, ref("sale_order_so0"))
+ pur_id = pur_obj.search(cr, uid, [('origin','=',so.name)])
+ po = pur_obj.browse(cr, uid, pur_id)[0]
+ assert(po.picking_ids),"Picking for purchase order has not been generated"
+-
+ Then I click on the "Products Received" button of Incoming Shipments
+-
+ !record {model: stock.partial.picking, id: stock_partial_picking_0}:
+ date: '2010-07-17 17:52:09'
+-
+ I click on the "Validate" button
+-
+ !python {model: stock.picking}: |
+ modules = self.pool.get('ir.module.module')
+ sale_order_obj = self.pool.get('sale.order')
+ pur_obj = self.pool.get('purchase.order')
+ mod_pur = modules.search(cr, uid, [('name','=','purchase')])
+ mod_brw = modules.browse(cr,uid,mod_pur)[0]
+ if (mod_brw.state == 'installed'):
+ so = sale_order_obj.browse(cr, uid, ref("sale_order_so0"))
+ pur_id = pur_obj.search(cr, uid, [('origin','=',so.name)])
+ po = pur_obj.browse(cr, uid, pur_id)[0]
+ pick_ser_id = self.search(cr, uid, [('purchase_id', '=', po.id )])
+ import netsvc
+ wf_service = netsvc.LocalService("workflow")
+ for pick in pick_ser_id:
+ wf_service.trg_validate(uid, 'stock.picking',pick,'button_done', cr)
+-
+ I verify that picking for purchase order has been done.
+-
+ !python {model: sale.order}: |
+ from tools.translate import _
+ modules = self.pool.get('ir.module.module')
+ mod_pur = modules.search(cr, uid, [('name','=','purchase')])
+ mod_brw = modules.browse(cr,uid,mod_pur)[0]
+ if(mod_brw.state == 'installed'):
+ pur_obj = self.pool.get('purchase.order')
+ so = self.browse(cr, uid, ref("sale_order_so0"))
+ pur_id = pur_obj.search(cr, uid, [('origin','=',so.name)])
+ po = pur_obj.browse(cr, uid, pur_id)[0]
+ picking_obj = self.pool.get('stock.picking')
+ ids = picking_obj.search(cr, uid, [('purchase_id', '=', po.id ) and ('state', '=', 'done')])
+ assert ids, _('Picking is not in the done state!')
+-
+ Then I done the picking
+-
+ !python {model: stock.picking }: |
+ import time
+ sale_order_obj = self.pool.get('sale.order')
+ so = sale_order_obj.browse(cr, uid, ref("sale_order_so0"))
+ picking_id = self.search(cr, uid, [('origin','=',so.name),('type','=','out')])
+ if picking_id:
+ pick=self.browse(cr,uid,picking_id[0])
+ pick.force_assign(cr, uid)
+ partial_datas = {
+ 'partner_id':pick.address_id.partner_id.id,
+ 'address_id': pick.address_id.id,
+ 'delivery_date' : time.strftime('%Y-%m-%d'),
+ }
+ move = pick.move_lines[0]
+ partial_datas['move%s'%(move.id)]= {
+ 'product_id': move.product_id.id,
+ 'product_qty': move.product_qty,
+ 'product_uom': move.product_uom.id,
+ }
+ self.do_partial(cr, uid, [pick.id],partial_datas)
+-
+ I verify that picking for sale order is in done state.
+-
+ !python {model: stock.picking }: |
+ sale_order_obj = self.pool.get('sale.order')
+ so = sale_order_obj.browse(cr, uid, ref("sale_order_so0"))
+ picking_id = self.search(cr, uid, [('origin','=',so.name),('type','=','out')])
+ pick = self.browse(cr,uid,picking_id[0])
+ assert (pick.state) =='done', "Picking for SO is not in done state."
+-
+ Then I done the delivery order
+-
+ !python {model: stock.picking }: |
+ import time
+ sale_order_obj = self.pool.get('sale.order')
+ so = sale_order_obj.browse(cr, uid, ref("sale_order_so0"))
+ picking_id = self.search(cr, uid, [('origin','=',so.name),('type','=','delivery')])
+ if picking_id:
+ pick=self.browse(cr,uid,picking_id[0])
+ pick.force_assign(cr, uid)
+ partial_datas = {
+ 'partner_id':pick.address_id.partner_id.id,
+ 'address_id': pick.address_id.id,
+ 'delivery_date' : time.strftime('%Y-%m-%d'),
+ }
+ move = pick.move_lines[0]
+ partial_datas['move%s'%(move.id)]= {
+ 'product_id': move.product_id.id,
+ 'product_qty': move.product_qty,
+ 'product_uom': move.product_uom.id,
+ }
+ self.do_partial(cr, uid, [pick.id],partial_datas)
+-
+ I verify that delivery state is done
+-
+ !python {model: stock.picking }: |
+ sale_order_obj = self.pool.get('sale.order')
+ so = sale_order_obj.browse(cr, uid, ref("sale_order_so0"))
+ picking_id = self.search(cr, uid, [('origin','=',so.name),('type','=','delivery')])
+ pick = self.browse(cr,uid,picking_id[0])
+ assert (pick.state) =='done', "Picking for SO is not in done state."
+-
+ I verify that a "Picked" has been set to true
+-
+ !python {model: sale.order}: |
+ so = self.browse(cr, uid, ref("sale_order_so0"))
+ assert (so.shipped == True), "Picked has not been set to True"
+-
+ I verify that a sale order is in done state
+-
+ !python {model: sale.order}: |
+ so = self.browse(cr, uid, ref("sale_order_so0"))
+ assert (so.state == 'done'), "Sale order is not in the done state."
diff --git a/addons/sale/test/picking_order_policy.yml b/addons/sale/test/picking_order_policy.yml
new file mode 100644
index 00000000000..d973f31d1f3
--- /dev/null
+++ b/addons/sale/test/picking_order_policy.yml
@@ -0,0 +1,329 @@
+-
+ In order to test the Sale module in OpenERP,
+ I create a Sale Order for Slider Mobile for qty 500 having Shipping Policy is 'Invoice from Picking'
+-
+ !record {model: sale.order, id: sale_order_so7}:
+ date_order: '2010-07-15'
+ invoice_quantity: order
+ name: Test_SO007
+ order_line:
+ - name: Slider Mobile
+ price_unit: 200
+ product_uom: product.product_uom_unit
+ product_uom_qty: 500.0
+ state: draft
+ delay: 7.0
+ product_id: sale.product_product_slidermobile0
+ product_uos_qty: 500.0
+ th_weight: 0.0
+ type: make_to_order
+ order_policy: picking
+ partner_id: sale.res_partner_cleartrail0
+ partner_invoice_id: sale.res_partner_address_2
+ partner_order_id: sale.res_partner_address_1
+ partner_shipping_id: sale.res_partner_address_3
+ picking_policy: direct
+ pricelist_id: product.list0
+ shop_id: sale.shop
+-
+ I confirm the sale order.
+-
+ !workflow {model: sale.order, action: order_confirm, ref: sale_order_so7}
+-
+ I verify that picking has been generated for the sale order.
+-
+ !python {model: sale.order}: |
+ so = self.browse(cr, uid, ref("sale_order_so7"))
+ assert so.picking_ids,"Picking has not been generated for sale_order_so7"
+-
+ Then I done the picking
+-
+ !python {model: stock.picking }: |
+ import time
+ sale_order_obj = self.pool.get('sale.order')
+ so = sale_order_obj.browse(cr, uid, ref("sale_order_so7"))
+ picking_id = self.search(cr, uid, [('origin','=',so.name),('type','=','out')])
+ if picking_id:
+ pick=self.browse(cr,uid,picking_id[0])
+ pick.force_assign(cr, uid)
+ partial_datas = {
+ 'partner_id':pick.address_id.partner_id.id,
+ 'address_id': pick.address_id.id,
+ 'delivery_date' : time.strftime('%Y-%m-%d'),
+ }
+ move = pick.move_lines[0]
+ partial_datas['move%s'%(move.id)]= {
+ 'product_id': move.product_id.id,
+ 'product_qty': move.product_qty,
+ 'product_uom': move.product_uom.id,
+ }
+ self.do_partial(cr, uid, [pick.id],partial_datas)
+-
+ Then I create invoice from picking
+-
+ !record {model: stock.invoice.onshipping, id: stock_invoice_onshipping_0}:
+ invoice_date: '2010-07-15'
+ journal_id: account.sales_journal
+ type: out_invoice
+-
+ Then I click on 'Create Invoices' button
+-
+ !python {model: stock.invoice.onshipping}: |
+ sale_obj=self.pool.get('sale.order')
+ sale_id=sale_obj.browse(cr, uid, ref("sale_order_so7"))
+ picking_obj = self.pool.get('stock.picking')
+ ids = picking_obj.search(cr, uid, [('origin', '=', sale_id.name)])
+ self.create_invoice(cr, uid, [ref("stock_invoice_onshipping_0")], {"lang": "en_US",
+ "search_default_available": 1, "tz": False, "active_model": "stock.picking",
+ "contact_display": "partner", "active_ids": ids, "active_id": ids[0]})
+-
+ I check that an invoice has been created.
+-
+ !python {model: sale.order}: |
+ sale_id=self.browse(cr, uid, ref("sale_order_so7"))
+ assert(sale_id.invoice_ids), "Invoice has not been created"
+-
+ I open the Invoice for the SO.
+-
+ !python {model: account.invoice}: |
+ sale_order_obj = self.pool.get('sale.order')
+ so = sale_order_obj.browse(cr, uid, ref("sale_order_so7"))
+ import netsvc
+ wf_service = netsvc.LocalService("workflow")
+ invoice_ids = so.invoice_ids
+ for invoice in invoice_ids:
+ wf_service.trg_validate(uid, 'account.invoice',invoice.id,'invoice_open', cr)
+-
+ Creating a account invoice pay entry.
+-
+ !record {model: account.invoice.pay, id: account_invoice_pay_tst1}:
+ amount: 255000.0
+ date: '2010-07-15'
+ journal_id: sale.account_journal_bankjournal0
+ name: tst
+ period_id: account.period_5
+-
+ I pay the invoice.
+-
+ !python {model: account.invoice.pay}: |
+ sale_order_obj = self.pool.get('sale.order')
+ so = sale_order_obj.browse(cr, uid, ref("sale_order_so7"))
+ self.wo_check(cr, uid, [ref("account_invoice_pay_tst1")], {"lang": "en_US", "tz":
+ False, "active_model": 'account.invoice', "active_ids": [so.invoice_ids[0].id], "type":
+ "out_invoice", "active_id": so.invoice_ids[0].id, })
+-
+ Creating an account invoice pay writeoff entry.
+-
+ !record {model: account.invoice.pay.writeoff, id: account_invoice_pay_writeoff_0}:
+ analytic_id: account.analytic_customers
+ comment: Write-Off
+ writeoff_acc_id: account.a_sale
+ writeoff_journal_id: sale.account_journal_bankjournal0
+-
+ Pay and Reconcile the Invoice.
+-
+ !python {model: account.invoice.pay.writeoff}: |
+ sale_order_obj = self.pool.get('sale.order')
+ so = sale_order_obj.browse(cr, uid, ref("sale_order_so7"))
+ self.pay_and_reconcile_writeoff(cr, uid, [ref("account_invoice_pay_writeoff_0")],
+ {"lang": 'en_US', "tz": False, "active_model": 'account.invoice', "active_ids":
+ [so.invoice_ids[0].id], "type": "out_invoice", "active_id": so.invoice_ids[0].id })
+-
+ I verify the invoice are in paid state or not.
+-
+ !python {model: account.invoice}: |
+ sale_order_obj = self.pool.get('sale.order')
+ so = sale_order_obj.browse(cr, uid, ref("sale_order_so7"))
+ invoice_ids = so.invoice_ids
+ for invoice in invoice_ids:
+ assert (invoice.state) =='paid', "Invoice for SO is not in done state."
+-
+ I check that Paid has been set to true.
+-
+ !python {model: sale.order}: |
+ sale_id=self.browse(cr, uid, ref("sale_order_so7"))
+ assert(sale_id.invoiced == True), "Paid has not been set to true"
+-
+ I verify that a procurement has been generated for so
+-
+ !python {model: procurement.order}: |
+ from tools.translate import _
+ sale_order_obj = self.pool.get('sale.order')
+ so = sale_order_obj.browse(cr, uid, ref("sale_order_so7"))
+ proc_ids = self.search(cr, uid, [('origin','=',so.name)])
+ assert proc_ids, _('No Procurements!')
+-
+ Then I click on the "Run Procurement" button
+-
+ !python {model: procurement.order}: |
+ sale_order_obj = self.pool.get('sale.order')
+ so = sale_order_obj.browse(cr, uid, ref("sale_order_so7"))
+ import netsvc
+ wf_service = netsvc.LocalService("workflow")
+ proc_ids = self.search(cr, uid, [('origin','=',so.name)])
+ for proc in proc_ids:
+ wf_service.trg_validate(uid, 'procurement.order',proc,'button_check', cr)
+-
+ I verify that a procurement state is "running"
+-
+ !python {model: procurement.order}: |
+ from tools.translate import _
+ modules = self.pool.get('ir.module.module')
+ mod_pur = modules.search(cr, uid, [('name','=','purchase')])
+ mod_brw = modules.browse(cr,uid,mod_pur)[0]
+ if (mod_brw.state == 'installed'):
+ sale_order_obj = self.pool.get('sale.order')
+ so = sale_order_obj.browse(cr, uid, ref("sale_order_so7"))
+ proc_ids = self.search(cr, uid, [('origin','=',so.name) and ('state','=','running')])
+ assert proc_ids, _('Procurement is not in the running state!')
+-
+ I verify that a purchase order has been generated
+-
+ !python {model: sale.order}: |
+ from tools.translate import _
+ modules = self.pool.get('ir.module.module')
+ mod_pur = modules.search(cr, uid, [('name','=','purchase')])
+ mod_brw = modules.browse(cr,uid,mod_pur)[0]
+ if (mod_brw.state == 'installed'):
+ so = self.browse(cr, uid, ref("sale_order_so7"))
+ pur_obj=self.pool.get('purchase.order')
+ pur_id=pur_obj.search(cr, uid, [('origin','=',so.name)])
+ assert pur_id, _('Purchase order has not been generated')
+-
+ I click on the "Confirm" button to confirm the purchase order
+-
+ !python {model: sale.order}: |
+ from tools.translate import _
+ modules = self.pool.get('ir.module.module')
+ mod_pur = modules.search(cr, uid, [('name','=','purchase')])
+ mod_brw = modules.browse(cr,uid,mod_pur)[0]
+ if (mod_brw.state == 'installed'):
+ pur_obj=self.pool.get('purchase.order')
+ so = self.browse(cr, uid, ref("sale_order_so7"))
+ import netsvc
+ wf_service = netsvc.LocalService("workflow")
+ pur_ids = pur_obj.search(cr, uid, [('origin','=',so.name)])
+ for pur in pur_ids:
+ wf_service.trg_validate(uid, 'purchase.order',pur,'purchase_confirm', cr)
+-
+ I click on the "Approved by supplier" button to approve the purchase order
+-
+ !python {model: sale.order}: |
+ from tools.translate import _
+ modules = self.pool.get('ir.module.module')
+ mod_pur = modules.search(cr, uid, [('name','=','purchase')])
+ mod_brw = modules.browse(cr,uid,mod_pur)[0]
+ if (mod_brw.state == 'installed'):
+ pur_obj = self.pool.get('purchase.order')
+ so = self.browse(cr, uid, ref("sale_order_so7"))
+ import netsvc
+ wf_service = netsvc.LocalService("workflow")
+ pur_ids = pur_obj.search(cr, uid, [('origin','=',so.name)])
+ for pur in pur_ids:
+ wf_service.trg_validate(uid, 'purchase.order',pur,'purchase_approve', cr)
+-
+ I verify that a picking related to purchase order has been generated.
+-
+ !python {model: sale.order}: |
+ modules = self.pool.get('ir.module.module')
+ mod_pur = modules.search(cr, uid, [('name','=','purchase')])
+ mod_brw = modules.browse(cr,uid,mod_pur)[0]
+ if (mod_brw.state == 'installed'):
+ pur_obj = self.pool.get('purchase.order')
+ so = self.browse(cr, uid, ref("sale_order_so7"))
+ pur_id = pur_obj.search(cr, uid, [('origin','=',so.name)])
+ po = pur_obj.browse(cr, uid, pur_id)[0]
+ assert(po.picking_ids),"Picking for purchase order has not been generated"
+-
+ Then I click on the "Products Received" button of Incoming Shipments
+-
+ !record {model: stock.partial.picking, id: stock_partial_picking_0}:
+ date: '2010-07-15 17:52:09'
+-
+ I click on the "Validate" button
+-
+ !python {model: stock.picking}: |
+ modules = self.pool.get('ir.module.module')
+ mod_pur = modules.search(cr, uid, [('name','=','purchase')])
+ mod_brw = modules.browse(cr,uid,mod_pur)[0]
+ if (mod_brw.state == 'installed'):
+ sale_order_obj = self.pool.get('sale.order')
+ pur_obj = self.pool.get('purchase.order')
+ so = sale_order_obj.browse(cr, uid, ref("sale_order_so7"))
+ pur_id = pur_obj.search(cr, uid, [('origin','=',so.name)])
+ po = pur_obj.browse(cr, uid, pur_id)[0]
+ pick_ser_id = self.search(cr, uid, [('purchase_id', '=', po.id )])
+ import netsvc
+ wf_service = netsvc.LocalService("workflow")
+ for pick in pick_ser_id:
+ wf_service.trg_validate(uid, 'stock.picking',pick,'button_done', cr)
+-
+ I verify that picking for purchase order has been done.
+-
+ !python {model: sale.order}: |
+ from tools.translate import _
+ modules = self.pool.get('ir.module.module')
+ mod_pur = modules.search(cr, uid, [('name','=','purchase')])
+ mod_brw = modules.browse(cr,uid,mod_pur)[0]
+ if (mod_brw.state == 'installed'):
+ pur_obj = self.pool.get('purchase.order')
+ so = self.browse(cr, uid, ref("sale_order_so7"))
+ pur_id = pur_obj.search(cr, uid, [('origin','=',so.name)])
+ po = pur_obj.browse(cr, uid, pur_id)[0]
+ picking_obj = self.pool.get('stock.picking')
+ ids = picking_obj.search(cr, uid, [('purchase_id', '=', po.id ) and ('state', '=', 'done')])
+ assert ids, _('Picking is not in the done state!')
+-
+ I verify that delivery order has been generated for sale order
+-
+ !python {model: stock.picking }: |
+ sale_order_obj = self.pool.get('sale.order')
+ so = sale_order_obj.browse(cr, uid, ref("sale_order_so7"))
+ picking_id = self.search(cr, uid, [('origin','=',so.name),('type','=','delivery')])
+ assert (picking_id),"Delivery order has not been generated"
+-
+ I verify that delivery has been done
+-
+ !python {model: stock.picking }: |
+ import time
+ sale_order_obj = self.pool.get('sale.order')
+ so = sale_order_obj.browse(cr, uid, ref("sale_order_so7"))
+ picking_id = self.search(cr, uid, [('origin','=',so.name),('type','=','delivery')])
+ if picking_id:
+ pick=self.browse(cr,uid,picking_id[0])
+ pick.force_assign(cr, uid)
+ partial_datas = {
+ 'partner_id':pick.address_id.partner_id.id,
+ 'address_id': pick.address_id.id,
+ 'delivery_date' : time.strftime('%Y-%m-%d'),
+ }
+ move = pick.move_lines[0]
+ partial_datas['move%s'%(move.id)]= {
+ 'product_id': move.product_id.id,
+ 'product_qty': move.product_qty,
+ 'product_uom': move.product_uom.id,
+ }
+ self.do_partial(cr, uid, [pick.id],partial_datas)
+-
+ I verify that delivery state is done
+-
+ !python {model: stock.picking }: |
+ sale_order_obj = self.pool.get('sale.order')
+ so = sale_order_obj.browse(cr, uid, ref("sale_order_so7"))
+ picking_id = self.search(cr, uid, [('origin','=',so.name),('type','=','delivery')])
+ if picking_id:
+ pick = self.browse(cr,uid,picking_id[0])
+ assert (pick.state) =='done', "Picking for SO is not in done state."
+-
+ I verify that a "Picked" has been set to true
+-
+ !python {model: sale.order}: |
+ so = self.browse(cr, uid, ref("sale_order_so7"))
+ assert (so.shipped == True), "Picked has not been set to True"
+-
+ I verify that a sale order is in done state
+-
+ !python {model: sale.order}: |
+ so = self.browse(cr, uid, ref("sale_order_so7"))
+ assert (so.state == 'done'), "Sale order is not in the done state."
+
diff --git a/addons/sale/test/postpaid_order_policy.yml b/addons/sale/test/postpaid_order_policy.yml
new file mode 100644
index 00000000000..056a8327435
--- /dev/null
+++ b/addons/sale/test/postpaid_order_policy.yml
@@ -0,0 +1,330 @@
+-
+ In order to test the Sale module in OpenERP,
+ I create a Sale Order for Slider Mobile for qty 500 having Shipping Policy is 'Invoice on order after Delivery'
+-
+ !record {model: sale.order, id: sale_order_so8}:
+ date_order: '2010-07-15'
+ invoice_quantity: order
+ name: Test_SO008
+ order_line:
+ - name: Slider Mobile
+ price_unit: 200.0
+ product_uom: product.product_uom_unit
+ product_uom_qty: 500.0
+ state: draft
+ delay: 7.0
+ product_id: sale.product_product_slidermobile0
+ product_uos_qty: 500.0
+ type: make_to_order
+ order_policy: postpaid
+ partner_id: sale.res_partner_cleartrail0
+ partner_invoice_id: sale.res_partner_address_2
+ partner_order_id: sale.res_partner_address_1
+ partner_shipping_id: sale.res_partner_address_3
+ picking_policy: direct
+ pricelist_id: product.list0
+ shop_id: sale.shop
+-
+ I confirm the Sale Order.
+-
+ !workflow {model: sale.order, action: order_confirm, ref: sale_order_so8}
+-
+ I verify that the picking has been generated for the sale order
+-
+ !python {model: sale.order}: |
+ so = self.browse(cr, uid, ref("sale_order_so8"))
+ assert so.picking_ids,"Picking has not been generated for sale_order_so8"
+-
+ Then I done the picking
+-
+ !python {model: stock.picking }: |
+ import time
+ sale_order_obj = self.pool.get('sale.order')
+ so = sale_order_obj.browse(cr, uid, ref("sale_order_so8"))
+ picking_id = self.search(cr, uid, [('origin','=',so.name),('type','=','out')])
+ if picking_id:
+ pick=self.browse(cr,uid,picking_id[0])
+ pick.force_assign(cr, uid)
+ partial_datas = {
+ 'partner_id':pick.address_id.partner_id.id,
+ 'address_id': pick.address_id.id,
+ 'delivery_date' : time.strftime('%Y-%m-%d'),
+ }
+ move = pick.move_lines[0]
+ partial_datas['move%s'%(move.id)]= {
+ 'product_id': move.product_id.id,
+ 'product_qty': move.product_qty,
+ 'product_uom': move.product_uom.id,
+ }
+ self.do_partial(cr, uid, [pick.id],partial_datas)
+-
+ I verify that picking order is in done state.
+-
+ !python {model: stock.picking }: |
+ sale_order_obj = self.pool.get('sale.order')
+ so = sale_order_obj.browse(cr, uid, ref("sale_order_so8"))
+ picking_id = self.search(cr, uid, [('origin','=',so.name),('type','=','out')])
+ if picking_id:
+ pick = self.browse(cr,uid,picking_id[0])
+ assert (pick.state == 'done'), "Picking for SO is not in done state."
+-
+ I verify that delivery order has been generated for sale order
+-
+ !python {model: stock.picking }: |
+ sale_order_obj = self.pool.get('sale.order')
+ so = sale_order_obj.browse(cr, uid, ref("sale_order_so8"))
+ picking_id = self.search(cr, uid, [('origin','=',so.name),('type','=','delivery')])
+ assert (picking_id),"Delivery order has not been generated"
+-
+ I click on the Products Sent button and then on the Validate button
+-
+ !python {model: stock.picking }: |
+ import time
+ sale_order_obj = self.pool.get('sale.order')
+ so = sale_order_obj.browse(cr, uid, ref("sale_order_so8"))
+ picking_id = self.search(cr, uid, [('origin','=',so.name),('type','=','delivery')])
+ if picking_id:
+ pick=self.browse(cr,uid,picking_id[0])
+ pick.force_assign(cr, uid)
+ partial_datas = {
+ 'partner_id':pick.address_id.partner_id.id,
+ 'address_id': pick.address_id.id,
+ 'delivery_date' : time.strftime('%Y-%m-%d'),
+ }
+ move = pick.move_lines[0]
+ partial_datas['move%s'%(move.id)]= {
+ 'product_id': move.product_id.id,
+ 'product_qty': move.product_qty,
+ 'product_uom': move.product_uom.id,
+ }
+ self.do_partial(cr, uid, [pick.id],partial_datas)
+-
+ I verify that delivery state is done
+-
+ !python {model: stock.picking }: |
+ sale_order_obj = self.pool.get('sale.order')
+ so = sale_order_obj.browse(cr, uid, ref("sale_order_so8"))
+ picking_id = self.search(cr, uid, [('origin','=',so.name),('type','=','delivery')])
+ if picking_id:
+ pick = self.browse(cr,uid,picking_id[0])
+ assert (pick.state) =='done', "Picking for SO is not in done state."
+-
+ I verify that a procurement has been generated for so
+-
+ !python {model: procurement.order}: |
+ from tools.translate import _
+ sale_order_obj = self.pool.get('sale.order')
+ so = sale_order_obj.browse(cr, uid, ref("sale_order_so8"))
+ proc_ids = self.search(cr, uid, [('origin','=',so.name)])
+ assert proc_ids, _('No Procurements!')
+-
+ Then I click on the "Run Procurement" button
+-
+ !python {model: procurement.order}: |
+ sale_order_obj = self.pool.get('sale.order')
+ so = sale_order_obj.browse(cr, uid, ref("sale_order_so8"))
+ import netsvc
+ wf_service = netsvc.LocalService("workflow")
+ proc_ids = self.search(cr, uid, [('origin','=',so.name)])
+ for proc in proc_ids:
+ wf_service.trg_validate(uid, 'procurement.order',proc,'button_check', cr)
+-
+ I verify that a procurement state is "running"
+-
+ !python {model: procurement.order}: |
+ from tools.translate import _
+ modules = self.pool.get('ir.module.module')
+ mod_pur = modules.search(cr, uid, [('name','=','purchase')])
+ mod_brw = modules.browse(cr,uid,mod_pur)[0]
+ if (mod_brw.state == 'installed'):
+ sale_order_obj = self.pool.get('sale.order')
+ so = sale_order_obj.browse(cr, uid, ref("sale_order_so8"))
+ proc_ids = self.search(cr, uid, [('origin','=',so.name) and ('state','=','running')])
+-
+ I verify that a purchase order has been generated
+-
+ !python {model: sale.order}: |
+ from tools.translate import _
+ modules = self.pool.get('ir.module.module')
+ mod_pur = modules.search(cr, uid, [('name','=','purchase')])
+ mod_brw = modules.browse(cr,uid,mod_pur)[0]
+ if (mod_brw.state == 'installed'):
+ so = self.browse(cr, uid, ref("sale_order_so8"))
+ pur_obj=self.pool.get('purchase.order')
+ pur_id=pur_obj.search(cr, uid, [('origin','=',so.name)])
+ assert pur_id, _('Purchase order has not been generated')
+-
+ I click on the "Confirm" button to confirm the purchase order
+-
+ !python {model: sale.order}: |
+ from tools.translate import _
+ modules = self.pool.get('ir.module.module')
+ mod_pur = modules.search(cr, uid, [('name','=','purchase')])
+ mod_brw = modules.browse(cr,uid,mod_pur)[0]
+ if (mod_brw.state == 'installed'):
+ pur_obj=self.pool.get('purchase.order')
+ so = self.browse(cr, uid, ref("sale_order_so8"))
+ import netsvc
+ wf_service = netsvc.LocalService("workflow")
+ pur_ids = pur_obj.search(cr, uid, [('origin','=',so.name)])
+ for pur in pur_ids:
+ wf_service.trg_validate(uid, 'purchase.order',pur,'purchase_confirm', cr)
+-
+ I click on the "Approved by supplier" button to approve the purchase order
+-
+ !python {model: sale.order}: |
+ from tools.translate import _
+ modules = self.pool.get('ir.module.module')
+ mod_pur = modules.search(cr, uid, [('name','=','purchase')])
+ mod_brw = modules.browse(cr,uid,mod_pur)[0]
+ if (mod_brw.state == 'installed'):
+ pur_obj = self.pool.get('purchase.order')
+ so = self.browse(cr, uid, ref("sale_order_so8"))
+ import netsvc
+ wf_service = netsvc.LocalService("workflow")
+ pur_ids = pur_obj.search(cr, uid, [('origin','=',so.name)])
+ for pur in pur_ids:
+ wf_service.trg_validate(uid, 'purchase.order',pur,'purchase_approve', cr)
+-
+ I verify that a picking related to purchase order has been generated.
+-
+ !python {model: sale.order}: |
+ modules = self.pool.get('ir.module.module')
+ mod_pur = modules.search(cr, uid, [('name','=','purchase')])
+ mod_brw = modules.browse(cr,uid,mod_pur)[0]
+ if (mod_brw.state == 'installed'):
+ pur_obj = self.pool.get('purchase.order')
+ so = self.browse(cr, uid, ref("sale_order_so8"))
+ pur_id = pur_obj.search(cr, uid, [('origin','=',so.name)])
+ po = pur_obj.browse(cr, uid, pur_id)[0]
+ assert(po.picking_ids),"Picking for purchase order has not been generated"
+-
+ Then I click on the "Products Received" button of Incoming Shipments
+-
+ !record {model: stock.partial.picking, id: stock_partial_picking_0}:
+ date: '2010-07-15 17:52:09'
+-
+ I click on the "Validate" button
+-
+ !python {model: stock.picking}: |
+ modules = self.pool.get('ir.module.module')
+ mod_pur = modules.search(cr, uid, [('name','=','purchase')])
+ mod_brw = modules.browse(cr,uid,mod_pur)[0]
+ if (mod_brw.state == 'installed'):
+ sale_order_obj = self.pool.get('sale.order')
+ pur_obj = self.pool.get('purchase.order')
+ so = sale_order_obj.browse(cr, uid, ref("sale_order_so8"))
+ pur_id = pur_obj.search(cr, uid, [('origin','=',so.name)])
+ po = pur_obj.browse(cr, uid, pur_id)[0]
+ pick_ser_id = self.search(cr, uid, [('purchase_id', '=', po.id )])
+ import netsvc
+ wf_service = netsvc.LocalService("workflow")
+ for pick in pick_ser_id:
+ wf_service.trg_validate(uid, 'stock.picking',pick,'button_done', cr)
+-
+ I verify that picking for purchase order has been done.
+-
+ !python {model: sale.order}: |
+ from tools.translate import _
+ modules = self.pool.get('ir.module.module')
+ mod_pur = modules.search(cr, uid, [('name','=','purchase')])
+ mod_brw = modules.browse(cr,uid,mod_pur)[0]
+ if (mod_brw.state == 'installed'):
+ pur_obj = self.pool.get('purchase.order')
+ so = self.browse(cr, uid, ref("sale_order_so8"))
+ pur_id = pur_obj.search(cr, uid, [('origin','=',so.name)])
+ po = pur_obj.browse(cr, uid, pur_id)[0]
+ picking_obj = self.pool.get('stock.picking')
+ ids = picking_obj.search(cr, uid, [('purchase_id', '=', po.id ) and ('state', '=', 'done')])
+ assert ids, _('Picking is not in the done state!')
+-
+ I verify that a "Picked" has been set to true
+-
+ !python {model: sale.order}: |
+ so = self.browse(cr, uid, ref("sale_order_so8"))
+ assert (so.shipped == True), "Picking is not done."
+-
+ I verify that an invoice has been generated for SO
+-
+ !python {model: sale.order}: |
+ so = self.browse(cr, uid, ref("sale_order_so8"))
+ assert so.invoice_ids, "Invoice has not been generated"
+-
+ I open the Invoice for the SO.
+-
+ !python {model: account.invoice}: |
+ sale_order_obj = self.pool.get('sale.order')
+ so = sale_order_obj.browse(cr, uid, ref("sale_order_so8"))
+ import netsvc
+ wf_service = netsvc.LocalService("workflow")
+ invoice_ids = so.invoice_ids
+ for invoice in invoice_ids:
+ wf_service.trg_validate(uid, 'account.invoice',invoice.id,'invoice_open', cr)
+-
+ Creating a account invoice pay entry.
+-
+ !record {model: account.invoice.pay, id: account_invoice_pay_tst0}:
+ amount: 100000.0
+ date: '2010-07-15'
+ journal_id: sale.account_journal_bankjournal0
+ name: test
+ period_id: account.period_5
+-
+ I pay the invoice.
+-
+ !python {model: account.invoice.pay}: |
+ modules = self.pool.get('ir.module.module')
+ mod_pur = modules.search(cr, uid, [('name','=','purchase')])
+ mod_brw = modules.browse(cr,uid,mod_pur)[0]
+ if (mod_brw.state == 'installed'):
+ sale_order_obj = self.pool.get('sale.order')
+ so = sale_order_obj.browse(cr, uid, ref("sale_order_so8"))
+ self.wo_check(cr, uid, [ref("account_invoice_pay_tst0")], {"lang": "en_US", "tz":
+ False, "active_model": 'account.invoice', "active_ids": [so.invoice_ids[0].id], "type":
+ "out_invoice", "active_id": so.invoice_ids[0].id})
+-
+ Creating an account invoice pay writeoff entry.
+-
+ !record {model: account.invoice.pay.writeoff, id: account_invoice_pay_writeoff_0}:
+ analytic_id: account.analytic_customers
+ comment: Write-Off
+ writeoff_acc_id: account.a_sale
+ writeoff_journal_id: sale.account_journal_bankjournal0
+-
+ Pay and Reconcile the Invoice.
+-
+ !python {model: account.invoice.pay.writeoff}: |
+ modules = self.pool.get('ir.module.module')
+ mod_pur = modules.search(cr, uid, [('name','=','purchase')])
+ mod_brw = modules.browse(cr,uid,mod_pur)[0]
+ if (mod_brw.state == 'installed'):
+ sale_order_obj = self.pool.get('sale.order')
+ so = sale_order_obj.browse(cr, uid, ref("sale_order_so8"))
+ self.pay_and_reconcile_writeoff(cr, uid, [ref("account_invoice_pay_writeoff_0")],
+ {"lang": 'en_US', "tz": False, "active_model": 'account.invoice', "active_ids":
+ [so.invoice_ids[0].id], "type": "out_invoice", "active_id": so.invoice_ids[0].id, })
+-
+ I verify the invoice are in paid state or not.
+-
+ !python {model: account.invoice}: |
+ modules = self.pool.get('ir.module.module')
+ mod_pur = modules.search(cr, uid, [('name','=','purchase')])
+ mod_brw = modules.browse(cr,uid,mod_pur)[0]
+ if (mod_brw.state == 'installed'):
+ sale_order_obj = self.pool.get('sale.order')
+ so = sale_order_obj.browse(cr, uid, ref("sale_order_so8"))
+ invoice_ids = so.invoice_ids
+ for invoice in invoice_ids:
+ assert (invoice.state) =='paid', "Invoice for SO is not in done state."
+-
+ I verify that Paid has been set to true.
+-
+ !python {model: sale.order}: |
+ sale_id=self.browse(cr, uid, ref("sale_order_so8"))
+ assert(sale_id.invoiced == True), "Paid has not been set to true"
+-
+ I verify that sale order is in done state
+-
+ !python {model: sale.order}: |
+ so = self.browse(cr, uid, ref("sale_order_so8"))
+ assert (so.state == 'done'), "Sale order is not in the done state."
\ No newline at end of file
diff --git a/addons/sale/test/prepaid_order_policy.yml b/addons/sale/test/prepaid_order_policy.yml
new file mode 100644
index 00000000000..fd7f04bede0
--- /dev/null
+++ b/addons/sale/test/prepaid_order_policy.yml
@@ -0,0 +1,284 @@
+-
+ I create a Sale Order for LG Viewty Smart for qty 500 having Shipping Policy is 'Payment Before Delivery'
+-
+ !record {model: sale.order, id: sale_order_so1}:
+ date_order: '2010-07-20'
+ invoice_quantity: order
+ name: Test_SO001
+ order_line:
+ - name: Slider Mobile
+ price_unit: 200
+ product_uom: product.product_uom_unit
+ product_uom_qty: 500.0
+ state: draft
+ delay: 7.0
+ product_id: sale.product_product_slidermobile0
+ product_uos_qty: 500.0
+ th_weight: 0.0
+ type: make_to_order
+ order_policy: prepaid
+ partner_id: sale.res_partner_cleartrail0
+ partner_invoice_id: sale.res_partner_address_2
+ partner_order_id: sale.res_partner_address_1
+ partner_shipping_id: sale.res_partner_address_3
+ picking_policy: direct
+ pricelist_id: product.list0
+ shop_id: sale.shop
+-
+ I confirm the sale order.
+-
+ !workflow {model: sale.order, action: order_confirm, ref: sale_order_so1}
+-
+ I verify whether the invoice has been generated for SO since Shipping policy is 'Payment Before Delivery'
+-
+ !python {model: sale.order}: |
+ so = self.browse(cr, uid, ref("sale_order_so1"))
+ assert so.invoice_ids, "Invoices has not been generated for sale_order_so1"
+-
+ I verify there are no pickings attached to this sale order
+-
+ !python {model: stock.picking }: |
+ sale_order_obj = self.pool.get('sale.order')
+ so = sale_order_obj.browse(cr, uid, ref("sale_order_so1"))
+ picking_id = self.search(cr, uid, [('origin','!=',so.name),(('type','=','out')and('type','=','delivery'))])
+ assert picking_id,"There is a picking attached to this sale order"
+-
+ I open the Invoice for the SO.
+-
+ !python {model: account.invoice}: |
+ sale_order_obj = self.pool.get('sale.order')
+ so = sale_order_obj.browse(cr, uid, ref("sale_order_so1"))
+ import netsvc
+ wf_service = netsvc.LocalService("workflow")
+ invoice_ids = so.invoice_ids
+ for invoice in invoice_ids:
+ wf_service.trg_validate(uid, 'account.invoice',invoice.id,'invoice_open', cr)
+-
+ Creating a account invoice pay entry.
+-
+ !record {model: account.invoice.pay, id: account_invoice_pay_tst1}:
+ amount: 85000.0
+ date: '2010-07-20'
+ journal_id: sale.account_journal_bankjournal0
+ name: tst
+ period_id: account.period_5
+-
+ I pay the invoice.
+-
+ !python {model: account.invoice.pay}: |
+ sale_order_obj = self.pool.get('sale.order')
+ so = sale_order_obj.browse(cr, uid, ref("sale_order_so1"))
+ self.wo_check(cr, uid, [ref("account_invoice_pay_tst1")], {"lang": "en_US", "tz":
+ False, "active_model": 'account.invoice', "active_ids": [so.invoice_ids[0].id], "type":
+ "out_invoice", "active_id": so.invoice_ids[0].id, })
+-
+ Creating an account invoice pay writeoff entry.
+-
+ !record {model: account.invoice.pay.writeoff, id: account_invoice_pay_writeoff_0}:
+ analytic_id: account.analytic_customers
+ comment: Write-Off
+ writeoff_acc_id: account.a_sale
+ writeoff_journal_id: sale.account_journal_bankjournal0
+-
+ Pay and Reconcile the Invoice.
+-
+ !python {model: account.invoice.pay.writeoff}: |
+ sale_order_obj = self.pool.get('sale.order')
+ so = sale_order_obj.browse(cr, uid, ref("sale_order_so1"))
+ self.pay_and_reconcile_writeoff(cr, uid, [ref("account_invoice_pay_writeoff_0")],
+ {"lang": 'en_US', "tz": False, "active_model": 'account.invoice', "active_ids":
+ [so.invoice_ids[0].id], "type": "out_invoice", "active_id": so.invoice_ids[0].id, })
+-
+ I verify the invoice is in done state or not.
+-
+ !python {model: account.invoice}: |
+ sale_order_obj = self.pool.get('sale.order')
+ so = sale_order_obj.browse(cr, uid, ref("sale_order_so1"))
+ invoice_id = self.search(cr, uid, [('origin','=',so.name) and ('state','=','paid')])
+ assert invoice_id, "Invoice for SO is not in done state."
+-
+ I check that Paid has been set to true.
+-
+ !python {model: sale.order}: |
+ sale_id=self.browse(cr, uid, ref("sale_order_so1"))
+ assert(sale_id.invoiced == True), "Paid has not been set to true"
+-
+ I verify the picking associated with the sale order sale_order_so1
+-
+ !python {model: sale.order}: |
+ so = self.browse(cr, uid, ref("sale_order_so1"))
+ assert so.picking_ids,"Picking has not been generated"
+-
+ Products are delivered to the Cleartrail Customer.
+-
+ !python {model: stock.picking }: |
+ import time
+ sale_order_obj = self.pool.get('sale.order')
+ so = sale_order_obj.browse(cr, uid, ref("sale_order_so1"))
+ picking_id = self.search(cr, uid, [('origin','=',so.name),('type','=','out')])
+ if picking_id:
+ pick=self.browse(cr,uid,picking_id[0])
+ pick.force_assign(cr, uid)
+ partial_datas = {
+ 'partner_id':pick.address_id.partner_id.id,
+ 'address_id': pick.address_id.id,
+ 'delivery_date' : time.strftime('%Y-%m-%d'),
+ }
+ move = pick.move_lines[0]
+ partial_datas['move%s'%(move.id)]= {
+ 'product_id': move.product_id.id,
+ 'product_qty': move.product_qty,
+ 'product_uom': move.product_uom.id,
+ }
+ self.do_partial(cr, uid, [pick.id],partial_datas)
+-
+ I verify that picking order is in done state.
+-
+ !python {model: stock.picking }: |
+ sale_order_obj = self.pool.get('sale.order')
+ so = sale_order_obj.browse(cr, uid, ref("sale_order_so1"))
+ picking_id = self.search(cr, uid, [('origin','=',so.name),('type','=','out')])
+ pick = self.browse(cr,uid,picking_id[0])
+ assert (pick.state) =='done', "Picking for SO is not in done state."
+-
+ I verify that a procurement has been generated for so
+-
+ !python {model: procurement.order}: |
+ from tools.translate import _
+ sale_order_obj = self.pool.get('sale.order')
+ so = sale_order_obj.browse(cr, uid, ref("sale_order_so1"))
+ proc_ids = self.search(cr, uid, [('origin','=',so.name)])
+ assert proc_ids, _('No Procurements!')
+-
+ Then I click on the "Run Procurement" button
+-
+ !python {model: procurement.order}: |
+ sale_order_obj = self.pool.get('sale.order')
+ so = sale_order_obj.browse(cr, uid, ref("sale_order_so1"))
+ import netsvc
+ wf_service = netsvc.LocalService("workflow")
+ proc_ids = self.search(cr, uid, [('origin','=',so.name)])
+ for proc in proc_ids:
+ wf_service.trg_validate(uid, 'procurement.order',proc,'button_check', cr)
+-
+ I verify that a procurement state is "running"
+-
+ !python {model: procurement.order}: |
+ from tools.translate import _
+ modules = self.pool.get('ir.module.module')
+ mod_pur = modules.search(cr, uid, [('name','=','purchase')])
+ mod_brw = modules.browse(cr,uid,mod_pur)[0]
+ if(mod_brw.state == 'installed'):
+ sale_order_obj = self.pool.get('sale.order')
+ so = sale_order_obj.browse(cr, uid, ref("sale_order_so1"))
+ proc_ids = self.search(cr, uid, [('origin','=',so.name) and ('state','=','running')])
+ assert proc_ids, _('Procurement is not in the running state!')
+-
+ I verify that a purchase order has been generated
+-
+ !python {model: sale.order}: |
+ from tools.translate import _
+ modules = self.pool.get('ir.module.module')
+ mod_pur = modules.search(cr, uid, [('name','=','purchase')])
+ mod_brw = modules.browse(cr,uid,mod_pur)[0]
+ if(mod_brw.state == 'installed'):
+ so = self.browse(cr, uid, ref("sale_order_so1"))
+ pur_obj=self.pool.get('purchase.order')
+ pur_id=pur_obj.search(cr, uid, [('origin','=',so.name)])
+ assert pur_id, _('Purchase order has not been generated')
+-
+ I click on the "Confirm" button to confirm the purchase order
+-
+ !python {model: sale.order}: |
+ from tools.translate import _
+ modules = self.pool.get('ir.module.module')
+ mod_pur = modules.search(cr, uid, [('name','=','purchase')])
+ mod_brw = modules.browse(cr,uid,mod_pur)[0]
+ if(mod_brw.state == 'installed'):
+ pur_obj=self.pool.get('purchase.order')
+ so = self.browse(cr, uid, ref("sale_order_so1"))
+ import netsvc
+ wf_service = netsvc.LocalService("workflow")
+ pur_ids = pur_obj.search(cr, uid, [('origin','=',so.name)])
+ for pur in pur_ids:
+ wf_service.trg_validate(uid, 'purchase.order',pur,'purchase_confirm', cr)
+-
+ I click on the "Approved by supplier" button to approve the purchase order
+-
+ !python {model: sale.order}: |
+ from tools.translate import _
+ modules = self.pool.get('ir.module.module')
+ mod_pur = modules.search(cr, uid, [('name','=','purchase')])
+ mod_brw = modules.browse(cr,uid,mod_pur)[0]
+ if (mod_brw.state == 'installed'):
+ pur_obj = self.pool.get('purchase.order')
+ so = self.browse(cr, uid, ref("sale_order_so1"))
+ import netsvc
+ wf_service = netsvc.LocalService("workflow")
+ pur_ids = pur_obj.search(cr, uid, [('origin','=',so.name)])
+ for pur in pur_ids:
+ wf_service.trg_validate(uid, 'purchase.order',pur,'purchase_approve', cr)
+-
+ I verify that a picking related to purchase order has been generated.
+-
+ !python {model: sale.order}: |
+ modules = self.pool.get('ir.module.module')
+ mod_pur = modules.search(cr, uid, [('name','=','purchase')])
+ mod_brw = modules.browse(cr,uid,mod_pur)[0]
+ if (mod_brw.state == 'installed'):
+ pur_obj = self.pool.get('purchase.order')
+ so = self.browse(cr, uid, ref("sale_order_so1"))
+ pur_id = pur_obj.search(cr, uid, [('origin','=',so.name)])
+ po = pur_obj.browse(cr, uid, pur_id)[0]
+ assert(po.picking_ids),"Picking for purchase order has not been generated"
+-
+ Then I click on the "Products Received" button of Incoming Shipments
+-
+ !record {model: stock.partial.picking, id: stock_partial_picking_0}:
+ date: '2010-07-20 17:52:09'
+-
+ I click on the "Validate" button
+-
+ !python {model: stock.picking}: |
+ modules = self.pool.get('ir.module.module')
+ sale_order_obj = self.pool.get('sale.order')
+ pur_obj = self.pool.get('purchase.order')
+ mod_pur = modules.search(cr, uid, [('name','=','purchase')])
+ mod_brw = modules.browse(cr,uid,mod_pur)[0]
+ if (mod_brw.state == 'installed'):
+ so = sale_order_obj.browse(cr, uid, ref("sale_order_so1"))
+ pur_id = pur_obj.search(cr, uid, [('origin','=',so.name)])
+ po = pur_obj.browse(cr, uid, pur_id)[0]
+ pick_ser_id = self.search(cr, uid, [('purchase_id', '=', po.id )])
+ import netsvc
+ wf_service = netsvc.LocalService("workflow")
+ for pick in pick_ser_id:
+ wf_service.trg_validate(uid, 'stock.picking',pick,'button_done', cr)
+-
+ I verify that picking for purchase order has been done.
+-
+ !python {model: sale.order}: |
+ from tools.translate import _
+ modules = self.pool.get('ir.module.module')
+ mod_pur = modules.search(cr, uid, [('name','=','purchase')])
+ mod_brw = modules.browse(cr,uid,mod_pur)[0]
+ if(mod_brw.state == 'installed'):
+ pur_obj = self.pool.get('purchase.order')
+ so = self.browse(cr, uid, ref("sale_order_so1"))
+ pur_id = pur_obj.search(cr, uid, [('origin','=',so.name)])
+ po = pur_obj.browse(cr, uid, pur_id)[0]
+ picking_obj = self.pool.get('stock.picking')
+ ids = picking_obj.search(cr, uid, [('purchase_id', '=', po.id ) and ('state', '=', 'done')])
+ assert ids, _('Picking is not in the done state!')
+-
+ I verify that a "Picked" has been set to true
+-
+ !python {model: sale.order}: |
+ so = self.browse(cr, uid, ref("sale_order_so1"))
+ assert (so.shipped == True), "Picking is not done."
+-
+ I verify that a sale order is in done state
+-
+ !python {model: sale.order}: |
+ so = self.browse(cr, uid, ref("sale_order_so1"))
+ assert (so.state == 'done'), "Sale order is not in the done state."
diff --git a/addons/sale/test/shipping_manual_sale_order.yml b/addons/sale/test/shipping_manual_sale_order.yml
deleted file mode 100644
index 1f5bc5fe10a..00000000000
--- a/addons/sale/test/shipping_manual_sale_order.yml
+++ /dev/null
@@ -1,384 +0,0 @@
--
- In order to test the sale module, I need to configure details regarding product & customer.
--
- I am going to sell my Mobile products to the customer with name Cleartrail
--
- I create View Account Type.
--
- !record {model: account.account.type, id: account_account_type_view0}:
- close_method: none
- code: View
- name: View
- sign: 1
--
- I create Income Account Type.
--
- !record {model: account.account.type, id: account_account_type_income0}:
- close_method: unreconciled
- code: Income
- name: Income
- sign: 1
--
- I create Expense Account Type.
--
- !record {model: account.account.type, id: account_account_type_expense0}:
- close_method: unreconciled
- code: Expense
- name: Expense
- sign: 1
--
- I create Cash Account Type.
--
- !record {model: account.account.type, id: account_account_type_cash0}:
- close_method: balance
- code: Cash
- name: Cash
- sign: 1
--
- I create Minimal Chart Account.
--
- !record {model: account.account, id: account_account_minimalchart0}:
- code: '0'
- company_id: base.main_company
- currency_mode: current
- name: Minimal Chart
- parent_left: 1
- parent_right: 12
- type: view
- user_type: account_account_type_view0
--
- I create Payable Account.
--
- !record {model: account.account, id: account_account_payable1}:
- code: AP
- company_id: base.main_company
- currency_mode: current
- name: Payable
- parent_id: account_account_minimalchart0
- parent_left: 2
- parent_right: 3
- reconcile: true
- type: payable
- user_type: account_account_type_expense0
--
- I create Receivable Account.
--
- !record {model: account.account, id: account_account_receivable0}:
- code: AR
- company_id: base.main_company
- currency_mode: current
- name: Receivable
- parent_id: account_account_minimalchart0
- parent_left: 4
- parent_right: 5
- reconcile: true
- type: receivable
- user_type: account_account_type_income0
--
- I create Cash Account.
--
- !record {model: account.account, id: account_account_cash0}:
- code: C
- company_id: base.main_company
- currency_mode: current
- name: Cash
- parent_id: account_account_minimalchart0
- parent_left: 6
- parent_right: 7
- type: other
- user_type: account_account_type_cash0
--
- I create Purchases Account.
--
- !record {model: account.account, id: account_account_purchases0}:
- code: P
- company_id: base.main_company
- currency_mode: current
- name: Purchases
- parent_id: account_account_minimalchart0
- parent_left: 8
- parent_right: 9
- type: other
- user_type: account_account_type_expense0
--
- I create Sales Account.
--
- !record {model: account.account, id: account_account_sales0}:
- code: S
- company_id: base.main_company
- currency_mode: current
- name: Sales
- parent_id: account_account_minimalchart0
- parent_left: 10
- parent_right: 11
- type: other
- user_type: account_account_type_income0
--
- I create Purchase Journal.
--
- !record {model: account.journal, id: account_journal_purchasejournal0}:
- code: PUJ
- company_id: base.main_company
- default_credit_account_id: account_account_purchases0
- default_debit_account_id: account_account_purchases0
- name: Purchase Journal
- sequence_id: account.sequence_purchase_journal
- type: purchase
- view_id: account.account_journal_view
--
- I create Sale Journal.
--
- !record {model: account.journal, id: account_journal_salejournal0}:
- code: SAJ
- company_id: base.main_company
- default_credit_account_id: account_account_sales0
- default_debit_account_id: account_account_sales0
- name: Sale Journal
- sequence_id: account.sequence_sale_journal
- type: sale
- view_id: account.account_journal_view
--
- I create Bank Journal.
--
- !record {model: account.journal, id: account_journal_bankjournal0}:
- code: BNK
- company_id: base.main_company
- default_credit_account_id: account_account_cash0
- default_debit_account_id: account_account_cash0
- name: Bank Journal
- sequence_id: account.sequence_journal
- type: cash
- view_id: account.account_journal_bank_view
--
- I create ir.property for account payable.
--
- !record {model: ir.property, id: ir_property_propertyaccountexpensecateg0}:
- company_id: base.main_company
- fields_id: account.field_res_partner_property_account_payable
- name: property_account_expense_categ
- value_reference: account.account,5
--
- I create ir.property for account receivable.
--
- !record {model: ir.property, id: ir_property_propertyaccountincomecateg0}:
- company_id: base.main_company
- fields_id: account.field_res_partner_property_account_receivable
- name: property_account_income_categ
- value_reference: account.account,6
--
- I create Partner category Customers.
--
- !record {model: res.partner.category, id: res_partner_category_customers0}:
- name: Customers
--
- I create Cleartrail Customer.
--
- !record {model: res.partner, id: res_partner_cleartrail0}:
- category_id:
- - res_partner_category_customers0
- name: Cleartrail
--
- I create contact address for Cleartrail.
--
- !record {model: res.partner.address, id: res_partner_address_1}:
- partner_id: res_partner_cleartrail0
- street: onam plaza, 14 B palasia A B Road
- type: contact
--
- I create invoice address for Cleartrail.
--
- !record {model: res.partner.address, id: res_partner_address_2}:
- partner_id: res_partner_cleartrail0
- street: sarda house 24 B palasia, A B Road
- type: invoice
--
- I create delivery address for Cleartrail.
--
- !record {model: res.partner.address, id: res_partner_address_3}:
- partner_id: res_partner_cleartrail0
- street: sangam house 15 B palasia, A B Road
- type: delivery
--
- Customer Cleartrail has specific instrument requirement regarding the stockable products.
--
- I define product category Mobile Products Sellable.
--
- !record {model: product.category, id: product_category_allproductssellable0}:
- name: Mobile Products Sellable
--
- I define product category Mobile Services.
--
- !record {model: product.category, id: product_category_services0}:
- name: Mobile Services
--
- I define New Chocolate Slider Mobile template.
--
- !record {model: product.template, id: product_template_newchocolateslidermobile0}:
- categ_id: product_category_allproductssellable0
- cost_method: standard
- list_price: 200.0
- mes_type: fixed
- name: New Chocolate Slider Mobile
- procure_method: make_to_order
- standard_price: 189.0
- supply_method: buy
- type: product
- uom_id: product.product_uom_unit
- uom_po_id: product.product_uom_unit
--
- I define New Chocolate Slider Mobile.
--
- !record {model: product.product, id: product_product_newchocolateslidermobile0}:
- categ_id: product_category_allproductssellable0
- cost_method: standard
- list_price: 200.0
- mes_type: fixed
- name: New Chocolate Slider Mobile
- pricelist_purchase: 'Default Purchase Pricelist (0.00) : 189.00\n'
- pricelist_sale: 'Public Pricelist (0.00) : 200.00\n'
- procure_method: make_to_order
- property_account_expense: sale.account_account_payable1
- property_account_income: sale.account_account_receivable0
- seller_delay: '1'
- standard_price: 189.0
- supply_method: buy
- type: product
- uom_id: product.product_uom_unit
- uom_po_id: product.product_uom_unit
--
- I create a Sale Order for LG Viewty Smart for qty 500 having order_policy manual.
--
- !record {model: sale.order, id: sale_order_so0}:
- date_order: '2010-05-12'
- invoice_quantity: order
- name: Test_SO002
- order_line:
- - name: New Chocolate Slider Mobile
- price_unit: 200.0
- product_uom: product.product_uom_unit
- product_uom_qty: 500.0
- state: draft
- delay: 7.0
- product_id: sale.product_product_newchocolateslidermobile0
- product_uos_qty: 500.0
- type: make_to_order
- order_policy: manual
- partner_id: sale.res_partner_cleartrail0
- partner_invoice_id: sale.res_partner_address_2
- partner_order_id: sale.res_partner_address_1
- partner_shipping_id: sale.res_partner_address_3
- picking_policy: direct
- pricelist_id: product.list0
- shop_id: sale.shop
--
- I confirm the Sale Order.
--
- !workflow {model: sale.order, action: order_confirm, ref: sale_order_so0}
--
- I click on Create Invoice button to create the invoice.
--
- !workflow {model: sale.order, action: manual_invoice, ref: sale_order_so0}
--
- I verify whether the invoice has been generated for SO
--
- !python {model: sale.order}: |
- so = self.browse(cr, uid, ref("sale_order_so0"))
- assert so.invoice_ids, "Invoices has not been generated for sale_order_so0"
--
- I open the Invoice for the SO.
--
- !python {model: account.invoice}: |
- sale_order_obj = self.pool.get('sale.order')
- so = sale_order_obj.browse(cr, uid, ref("sale_order_so0"))
- import netsvc
- wf_service = netsvc.LocalService("workflow")
- invoice_ids = so.invoice_ids
- for invoice in invoice_ids:
- wf_service.trg_validate(uid, 'account.invoice',invoice.id,'invoice_open', cr)
--
- Creating a account invoice pay entry.
--
- !record {model: account.invoice.pay, id: account_invoice_pay_tst0}:
- amount: 100000.0
- date: '2010-05-10'
- journal_id: sale.account_journal_bankjournal0
- name: test
- period_id: account.period_5
--
- I pay the invoice.
--
- !python {model: account.invoice.pay}: |
- sale_order_obj = self.pool.get('sale.order')
- so = sale_order_obj.browse(cr, uid, ref("sale_order_so0"))
- self.wo_check(cr, uid, [ref("account_invoice_pay_tst0")], {"lang": "en_US", "tz":
- False, "active_model": 'account.invoice', "active_ids": [so.invoice_ids[0].id], "type":
- "out_invoice", "active_id": so.invoice_ids[0].id})
-
-
--
- Creating an account invoice pay writeoff entry.
--
- !record {model: account.invoice.pay.writeoff, id: account_invoice_pay_writeoff_0}:
- analytic_id: account.analytic_customers
- comment: Write-Off
- writeoff_acc_id: account.a_sale
- writeoff_journal_id: sale.account_journal_bankjournal0
-
-
--
- Pay and Reconcile the Invoice.
--
- !python {model: account.invoice.pay.writeoff}: |
- sale_order_obj = self.pool.get('sale.order')
- so = sale_order_obj.browse(cr, uid, ref("sale_order_so0"))
- self.pay_and_reconcile_writeoff(cr, uid, [ref("account_invoice_pay_writeoff_0")],
- {"lang": 'en_US', "tz": False, "active_model": 'account.invoice', "active_ids":
- [so.invoice_ids[0].id], "type": "out_invoice", "active_id": so.invoice_ids[0].id, })
--
- I verify the invoice are in paid state or not.
--
- !python {model: account.invoice}: |
- sale_order_obj = self.pool.get('sale.order')
- so = sale_order_obj.browse(cr, uid, ref("sale_order_so0"))
- invoice_ids = so.invoice_ids
- for invoice in invoice_ids:
- assert (invoice.state) =='paid', "Invoice for SO is not in done state."
--
- I verify the picking associated with the sale order sale_order_so0.
--
- !python {model: sale.order}: |
- so = self.browse(cr, uid, ref("sale_order_so0"))
- assert so.picking_ids,"Picking has not been generated for sale_order_so0"
--
- Products are delivered to the Cleartrail Customer.
--
- !python {model: stock.picking }: |
- import time
- sale_order_obj = self.pool.get('sale.order')
- so = sale_order_obj.browse(cr, uid, ref("sale_order_so0"))
- picking_id = self.search(cr, uid, [('origin','=',so.name),('type','=','out')])
- if picking_id:
- pick=self.browse(cr,uid,picking_id[0])
- pick.force_assign(cr, uid)
- partial_datas = {
- 'partner_id':pick.address_id.partner_id.id,
- 'address_id': pick.address_id.id,
- 'delivery_date' : time.strftime('%Y-%m-%d'),
- }
- move = pick.move_lines[0]
- partial_datas['move%s'%(move.id)]= {
- 'product_id': move.product_id.id,
- 'product_qty': move.product_qty,
- 'product_uom': move.product_uom.id,
- }
- self.do_partial(cr, uid, [pick.id],partial_datas)
--
- I verify that picking order is in done state.
--
- !python {model: stock.picking }: |
- sale_order_obj = self.pool.get('sale.order')
- so = sale_order_obj.browse(cr, uid, ref("sale_order_so0"))
- picking_id = self.search(cr, uid, [('origin','=',so.name),('type','=','out')])
- if picking_id:
- pick = self.browse(cr,uid,picking_id[0])
- assert (pick.state) =='done', "Picking for SO is not in done state."
diff --git a/addons/sale/test/so_make_line_invoice.yml b/addons/sale/test/so_make_line_invoice.yml
index c09e4bf2c11..9725a169b2c 100644
--- a/addons/sale/test/so_make_line_invoice.yml
+++ b/addons/sale/test/so_make_line_invoice.yml
@@ -1,307 +1,29 @@
-
- In order to test the sale module in the Open-ERP, I need to configure details regarding product & customer.
--
- I am going to sell my Mobile products to the customer with name Cleartrail
--
- I create View Account Type.
--
- !record {model: account.account.type, id: account_account_type_view0}:
- close_method: none
- code: View
- name: View
- sign: 1
--
- I create Income Account Type.
--
- !record {model: account.account.type, id: account_account_type_income0}:
- close_method: unreconciled
- code: Income
- name: Income
- sign: 1
--
- I create Expense Account Type.
--
- !record {model: account.account.type, id: account_account_type_expense0}:
- close_method: unreconciled
- code: Expense
- name: Expense
- sign: 1
--
- I create Cash Account Type.
--
- !record {model: account.account.type, id: account_account_type_cash0}:
- close_method: balance
- code: Cash
- name: Cash
- sign: 1
--
- I create Minimal Chart Account.
--
- !record {model: account.account, id: account_account_minimalchart0}:
- code: '0'
- company_id: base.main_company
- currency_mode: current
- name: Minimal Chart
- parent_left: 1
- parent_right: 12
- type: view
- user_type: account_account_type_view0
--
- I create Payable Account.
--
- !record {model: account.account, id: account_account_payable1}:
- code: AP
- company_id: base.main_company
- currency_mode: current
- name: Payable
- parent_id: account_account_minimalchart0
- parent_left: 2
- parent_right: 3
- reconcile: true
- type: payable
- user_type: account_account_type_expense0
--
- I create Receivable Account.
--
- !record {model: account.account, id: account_account_receivable0}:
- code: AR
- currency_mode: current
- name: Receivable
- parent_id: account_account_minimalchart0
- parent_left: 4
- parent_right: 5
- reconcile: true
- type: receivable
- user_type: account_account_type_income0
--
- I create Cash Account.
--
- !record {model: account.account, id: account_account_cash0}:
- code: C
- currency_mode: current
- name: Cash
- parent_id: account_account_minimalchart0
- parent_left: 6
- parent_right: 7
- type: other
- user_type: account_account_type_cash0
--
- I create Purchases Account.
--
- !record {model: account.account, id: account_account_purchases0}:
- code: P
- company_id: base.main_company
- currency_mode: current
- name: Purchases
- parent_id: account_account_minimalchart0
- parent_left: 8
- parent_right: 9
- type: other
- user_type: account_account_type_expense0
--
- I create Sales Account.
--
- !record {model: account.account, id: account_account_sales0}:
- code: S
- company_id: base.main_company
- currency_mode: current
- name: Sales
- parent_id: account_account_minimalchart0
- parent_left: 10
- parent_right: 11
- type: other
- user_type: account_account_type_income0
--
- I create Purchase Journal.
--
- !record {model: account.journal, id: account_journal_purchasejournal0}:
- code: PUJ
- company_id: base.main_company
- default_credit_account_id: account_account_purchases0
- default_debit_account_id: account_account_purchases0
- name: Purchase Journal
- sequence_id: account.sequence_purchase_journal
- type: purchase
- view_id: account.account_journal_view
--
- I create Sale Journal.
--
- !record {model: account.journal, id: account_journal_salejournal0}:
- code: SAJ
- company_id: base.main_company
- default_credit_account_id: account_account_sales0
- default_debit_account_id: account_account_sales0
- name: Sale Journal
- sequence_id: account.sequence_sale_journal
- type: sale
- view_id: account.account_journal_view
--
- I create Bank Journal.
--
- !record {model: account.journal, id: account_journal_bankjournal0}:
- code: BNK
- default_credit_account_id: account_account_cash0
- default_debit_account_id: account_account_cash0
- name: Bank Journal
- sequence_id: account.sequence_journal
- type: cash
- view_id: account.account_journal_bank_view
--
- I create ir.property for account payable.
--
- !record {model: ir.property, id: ir_property_propertyaccountexpensecateg0}:
- company_id: base.main_company
- fields_id: account.field_res_partner_property_account_payable
- name: property_account_expense_categ
- value_reference: account.account,5
--
- I create ir.property for account receivable.
--
- !record {model: ir.property, id: ir_property_propertyaccountincomecateg0}:
- company_id: base.main_company
- fields_id: account.field_res_partner_property_account_receivable
- name: property_account_income_categ
- value_reference: account.account,6
--
- I create Partner category Customers.
--
- !record {model: res.partner.category, id: res_partner_category_customers0}:
- name: Customers
--
- I create Cleartrail Customer.
--
- !record {model: res.partner, id: res_partner_cleartrail0}:
- category_id:
- - res_partner_category_customers0
- name: Cleartrail
--
- I create contact address for Cleartrail.
--
- !record {model: res.partner.address, id: res_partner_address_1}:
- partner_id: res_partner_cleartrail0
- street: onam plaza, 14 B palasia A B Road
- type: contact
--
- I create invoice address for Cleartrail.
--
- !record {model: res.partner.address, id: res_partner_address_2}:
- partner_id: res_partner_cleartrail0
- street: sarda house 24 B palasia, A B Road
- type: invoice
--
- I create delivery address for Cleartrail.
--
- !record {model: res.partner.address, id: res_partner_address_3}:
- partner_id: res_partner_cleartrail0
- street: sangam house 15 B palasia, A B Road
- type: delivery
--
- Customer Cleartrail has specific instrument requirement regarding the stockable products.
--
- I define product category Mobile Products Sellable.
--
- !record {model: product.category, id: product_category_allproductssellable0}:
- name: Mobile Products Sellable
--
- I define product category Mobile Services.
--
- !record {model: product.category, id: product_category_services0}:
- name: Mobile Services
--
- I define LG Viewty Smart product template.
--
- !record {model: product.template, id: product_template_lgviewtysmart0}:
- categ_id: product_category_allproductssellable0
- cost_method: standard
- list_price: 170.0
- mes_type: fixed
- name: LG Viewty Smart
- procure_method: make_to_order
- standard_price: 160.0
- supply_method: produce
- type: product
- uom_id: product.product_uom_unit
- uom_po_id: product.product_uom_unit
--
- I define LG Viewty Smart product.
--
- !record {model: product.product, id: product_product_lgviewtysmart0}:
- categ_id: product_category_allproductssellable0
- cost_method: standard
- list_price: 170.0
- mes_type: fixed
- name: LG Viewty Smart
- pricelist_purchase: 'Default Purchase Pricelist (0.00) : 160.00\n'
- pricelist_sale: 'Public Pricelist (0.00) : 170.00\n'
- procure_method: make_to_order
- property_account_expense: sale.account_account_payable1
- property_account_income: sale.account_account_receivable0
- seller_delay: '1'
- standard_price: 160.0
- supply_method: produce
- type: product
- uom_id: product.product_uom_unit
- uom_po_id: product.product_uom_unit
--
- I define New Chocolate Slider Mobile template.
--
- !record {model: product.template, id: product_template_newchocolateslidermobile0}:
- categ_id: product_category_allproductssellable0
- cost_method: standard
- list_price: 200.0
- mes_type: fixed
- name: New Chocolate Slider Mobile
- procure_method: make_to_order
- standard_price: 189.0
- supply_method: buy
- type: product
- uom_id: product.product_uom_unit
- uom_po_id: product.product_uom_unit
--
- I define New Chocolate Slider Mobile.
--
- !record {model: product.product, id: product_product_newchocolateslidermobile0}:
- categ_id: product_category_allproductssellable0
- cost_method: standard
- list_price: 200.0
- mes_type: fixed
- name: New Chocolate Slider Mobile
- pricelist_purchase: 'Default Purchase Pricelist (0.00) : 189.00\n'
- pricelist_sale: 'Public Pricelist (0.00) : 200.00\n'
- procure_method: make_to_order
- property_account_expense: sale.account_account_payable1
- property_account_income: sale.account_account_receivable0
- seller_delay: '1'
- standard_price: 189.0
- supply_method: buy
- type: product
- uom_id: product.product_uom_unit
- uom_po_id: product.product_uom_unit
--
- I create a Sale Order for LG Viewty Smart for qty 500 having order_policy manual.
+ In order to test the invoices based on sale order lines of sales module in OpenERP
+ I create a Sale Order for two products LG Viewty Smart and Slider mobile for qty 100 having order_policy manual.
-
!record {model: sale.order, id: sale_order_so3}:
- date_order: '2010-05-12'
+ date_order: '2010-07-12'
invoice_quantity: order
name: Test_SO003
order_line:
- - name: New Chocolate Slider Mobile
+ - name: Slider Mobile
price_unit: 200.0
product_uom: product.product_uom_unit
- product_uom_qty: 500.0
+ product_uom_qty: 100.0
state: draft
delay: 7.0
- product_id: sale.product_product_newchocolateslidermobile0
- product_uos_qty: 500.0
+ product_id: sale.product_product_slidermobile0
+ product_uos_qty: 100.0
type: make_to_order
- name: LG Viewty Smart
price_unit: 170.0
product_uom: product.product_uom_unit
- product_uom_qty: 500.0
+ product_uom_qty: 100.0
state: draft
delay: 7.0
product_id: sale.product_product_lgviewtysmart0
- product_uos_qty: 500.0
+ product_uos_qty: 100.0
th_weight: 0.0
type: make_to_order
order_policy: manual
@@ -317,23 +39,205 @@
-
!workflow {model: sale.order, action: order_confirm, ref: sale_order_so3}
-
- I create an invoice on sale order line.
+ I click on the "Create Invoice" button of sale order line
-
- !record {model: sale.order.line.make.invoice, id: sale_order_line_make_invoice_0}:
- {}
--
- invoice is created for specific sale order line.
--
- !python {model: sale.order.line.make.invoice}: |
+ !python {model: sale.order.line}: |
sale_order_obj = self.pool.get('sale.order')
so = sale_order_obj.browse(cr, uid, ref("sale_order_so3"))
- sol = so.order_line[0]
- self.make_invoices(cr, uid, [ref("sale_order_line_make_invoice_0")], {"lang":
- 'en_US', "active_model": "sale.order.line", "active_ids": [ref(sol.id)], "tz":
- False, "active_id": ref(sol.id), })
+ sol = so.order_line[0]
+ self.create_sale_order_line_invoice(cr, uid, [sol.id], {"lang": "en_US",
+ "tz": False, "active_model": "ir.ui.menu", "active_ids": [ref("sale.menu_invoicing_sales_order_lines")],
+ "search_default_uninvoiced": 1, "active_id": ref("sale.menu_invoicing_sales_order_lines"),
+ })
-
- I verify that invoice regarding sale order line has been created.
+ I verify that "Invoiced" has been set to True.
+-
+ !python {model: sale.order}: |
+ sale_id=self.browse(cr, uid, ref("sale_order_so3"))
+ sol = sale_id.order_line[0]
+ assert(sol.invoiced == True), "Invoiced has not been set to true"
+-
+ I verify that an invoice for sale order line has been created.
-
!python {model: sale.order}: |
so = self.browse(cr, uid, ref("sale_order_so3"))
- assert so.invoice_ids, "Invoices has not been generated for sale_order_so0"
+ assert so.invoice_ids, "Invoices has not been generated for sale_order_so3"
+-
+ I click on the Create button of invoice
+-
+ !python {model: account.invoice}: |
+ sale_order_obj = self.pool.get('sale.order')
+ so = sale_order_obj.browse(cr, uid, ref("sale_order_so3"))
+ import netsvc
+ wf_service = netsvc.LocalService("workflow")
+ invoice_ids = so.invoice_ids
+ for invoice in invoice_ids:
+ wf_service.trg_validate(uid, 'account.invoice',invoice.id,'invoice_open', cr)
+-
+ I verify that an invoice state has transit from draft to open state
+-
+ !python {model: account.invoice}: |
+ sale_order_obj = self.pool.get('sale.order')
+ so = sale_order_obj.browse(cr, uid, ref("sale_order_so3"))
+ invoice_id = self.search(cr, uid, [('origin','=',so.name) and ('state','=','open')])
+ assert invoice_id, "Invoice is not in the open state"
+-
+ Creating an account invoice pay entry.
+-
+ !record {model: account.invoice.pay, id: account_invoice_pay_tst0}:
+ amount: 20000.0
+ date: '2010-07-12'
+ journal_id: sale.account_journal_bankjournal0
+ name: test
+ period_id: account.period_5
+-
+ I pay the invoice.
+-
+ !python {model: account.invoice.pay}: |
+ sale_order_obj = self.pool.get('sale.order')
+ so = sale_order_obj.browse(cr, uid, ref("sale_order_so3"))
+ self.wo_check(cr, uid, [ref("account_invoice_pay_tst0")], {"lang": "en_US", "active_model": "account.invoice",
+ "tz":False,"record_id": so.invoice_ids[0].id, "active_ids": [so.invoice_ids[0].id], "type":
+ "out_invoice", "active_id": so.invoice_ids[0].id})
+-
+ Creating an account invoice pay writeoff entry.
+-
+ !record {model: account.invoice.pay.writeoff, id: account_invoice_pay_writeoff_0}:
+ analytic_id: account.analytic_customers
+ comment: Write-Off
+ writeoff_acc_id: account.a_sale
+ writeoff_journal_id: sale.account_journal_bankjournal0
+-
+ Pay and Reconcile the Invoice.
+-
+ !python {model: account.invoice.pay.writeoff}: |
+ sale_order_obj = self.pool.get('sale.order')
+ so = sale_order_obj.browse(cr, uid, ref("sale_order_so3"))
+ self.pay_and_reconcile_writeoff(cr, uid, [ref("account_invoice_pay_writeoff_0")],
+ {"lang": 'en_US', "tz": False, "active_model": 'account.invoice', "active_ids":
+ [so.invoice_ids[0].id], "type": "out_invoice", "active_id": so.invoice_ids[0].id, })
+-
+ I verify that an invoice is in done state.
+-
+ !python {model: account.invoice}: |
+ sale_order_obj = self.pool.get('sale.order')
+ so = sale_order_obj.browse(cr, uid, ref("sale_order_so3"))
+ invoice_id = self.search(cr, uid, [('origin','=',so.name) and ('state','=','paid')])
+ assert invoice_id, "Invoice for SO is not in done state."
+-
+ I verify that Paid has been set to true.
+-
+ !python {model: sale.order}: |
+ sale_id=self.browse(cr, uid, ref("sale_order_so3"))
+ assert(sale_id.invoiced == True), "Paid has not been set to true"
+-
+ I click on the "Create Invoice" button of sale order and verify that it gives a warning message
+-
+ !python {model: sale.order}: |
+ sale_order_obj = self.pool.get('sale.order')
+ import netsvc
+ wf_service = netsvc.LocalService("workflow")
+ try:
+ wf_service.trg_validate(uid, 'sale.order',ref("sale_order_so3"),'manual_invoice', cr)
+ except:
+ pass
+-
+ I create an invoice for another sale order line.
+-
+ I click on the "Create Invoice" button of sale order line
+-
+ !python {model: sale.order.line}: |
+ sale_order_obj = self.pool.get('sale.order')
+ so = sale_order_obj.browse(cr, uid, ref("sale_order_so3"))
+ sol = so.order_line[1]
+ self.create_sale_order_line_invoice(cr, uid, [sol.id], {"lang": "en_US",
+ "tz": False, "active_model": "ir.ui.menu", "active_ids": [ref("sale.menu_invoicing_sales_order_lines")],
+ "search_default_uninvoiced": 1, "active_id": ref("sale.menu_invoicing_sales_order_lines"),
+ })
+-
+ I verify that invoice for sale order line has been created.
+-
+ !python {model: sale.order}: |
+ so = self.browse(cr, uid, ref("sale_order_so3"))
+ assert so.invoice_ids[1], "Invoices has not been generated for sale_order_so3"
+-
+ I verify that "Invoiced" has been set to True.
+-
+ !python {model: sale.order}: |
+ sale_id=self.browse(cr, uid, ref("sale_order_so3"))
+ sol = sale_id.order_line[1]
+ assert(sol.invoiced == True), "Invoiced has not been set to true"
+-
+ I verify that "Paid" has been set to False.
+-
+ !python {model: sale.order}: |
+ sale_id=self.browse(cr, uid, ref("sale_order_so3"))
+ assert(sale_id.invoiced == False), "Paid has not been set to true"
+-
+ I open the Invoice for the SO.
+-
+ !python {model: account.invoice}: |
+ sale_order_obj = self.pool.get('sale.order')
+ so = sale_order_obj.browse(cr, uid, ref("sale_order_so3"))
+ import netsvc
+ wf_service = netsvc.LocalService("workflow")
+ invoice_ids = so.invoice_ids
+ for invoice in invoice_ids:
+ wf_service.trg_validate(uid, 'account.invoice',invoice.id,'invoice_open', cr)
+-
+ I verify that an invoice state has transit from draft to open state
+-
+ !python {model: account.invoice}: |
+ sale_order_obj = self.pool.get('sale.order')
+ so = sale_order_obj.browse(cr, uid, ref("sale_order_so3"))
+ invoice_id = self.search(cr, uid, [('origin','=',so.name) and ('state','=','open')])
+ assert invoice_id, "Invoice is not in the open state"
+-
+ Creating a account invoice pay entry.
+-
+ !record {model: account.invoice.pay, id: account_invoice_pay_tst1}:
+ amount: 17000.0
+ date: '2010-07-12'
+ journal_id: sale.account_journal_bankjournal0
+ name: test
+ period_id: account.period_5
+-
+ I pay the invoice.
+-
+ !python {model: account.invoice.pay}: |
+ sale_order_obj = self.pool.get('sale.order')
+ so = sale_order_obj.browse(cr, uid, ref("sale_order_so3"))
+ self.wo_check(cr, uid, [ref("account_invoice_pay_tst1")], {"lang": "en_US", "active_model": "account.invoice",
+ "tz":False,"record_id": so.invoice_ids[1].id, "active_ids": [so.invoice_ids[1].id], "type":
+ "out_invoice", "active_id": so.invoice_ids[1].id})
+-
+ Creating an account invoice pay writeoff entry.
+-
+ !record {model: account.invoice.pay.writeoff, id: account_invoice_pay_writeoff_1}:
+ analytic_id: account.analytic_customers
+ comment: Write-Off
+ writeoff_acc_id: account.a_sale
+ writeoff_journal_id: sale.account_journal_bankjournal0
+-
+ Pay and Reconcile the Invoice.
+-
+ !python {model: account.invoice.pay.writeoff}: |
+ sale_order_obj = self.pool.get('sale.order')
+ so = sale_order_obj.browse(cr, uid, ref("sale_order_so3"))
+ self.pay_and_reconcile_writeoff(cr, uid, [ref("account_invoice_pay_writeoff_1")],
+ {"lang": 'en_US', "tz": False, "active_model": 'account.invoice', "active_ids":
+ [so.invoice_ids[1].id], "type": "out_invoice", "active_id": so.invoice_ids[1].id})
+-
+ I verify the invoice is in done state.
+-
+ !python {model: account.invoice}: |
+ sale_order_obj = self.pool.get('sale.order')
+ so = sale_order_obj.browse(cr, uid, ref("sale_order_so3"))
+ invoice_id = self.search(cr, uid, [('origin','=',so.name) and ('state','=','paid')])
+ assert invoice_id, "Invoice for SO is not in done state."
+-
+ I verify that Paid has been set to true.
+-
+ !python {model: sale.order}: |
+ sale_id=self.browse(cr, uid, ref("sale_order_so3"))
+ assert(sale_id.invoiced == True), "Paid has not been set to true"
\ No newline at end of file
diff --git a/addons/stock/stock_view.xml b/addons/stock/stock_view.xml
index 5668ed673d4..5980870f89f 100644
--- a/addons/stock/stock_view.xml
+++ b/addons/stock/stock_view.xml
@@ -785,7 +785,7 @@
form
-
+
@@ -1185,7 +1185,6 @@
-
@@ -1220,7 +1219,7 @@
+ states="draft,assigned,confirmed"/>
-
+
-
diff --git a/addons/stock/test/stock_test.yml b/addons/stock/test/stock_test.yml
index 33b3350d628..442cc8735b9 100644
--- a/addons/stock/test/stock_test.yml
+++ b/addons/stock/test/stock_test.yml
@@ -192,7 +192,7 @@
seller_ids:
- delay: 1
name: stock.res_partner_shawtrust0
- qty: 5.0
+ min_qty: 5.0
supply_method: buy
type: product
uom_id: product.product_uom_unit
@@ -213,7 +213,7 @@
seller_ids:
- delay: 1
name: res_partner_shawtrust0
- qty: 5.0
+ min_qty: 5.0
supply_method: buy
type: product
uom_id: product.product_uom_unit
diff --git a/addons/stock/wizard/stock_change_standard_price.py b/addons/stock/wizard/stock_change_standard_price.py
index 149b0b04e84..7d0be0b333b 100644
--- a/addons/stock/wizard/stock_change_standard_price.py
+++ b/addons/stock/wizard/stock_change_standard_price.py
@@ -26,7 +26,10 @@ class change_standard_price(osv.osv_memory):
_name = "stock.change.standard.price"
_description = "Change Standard Price"
_columns = {
- 'new_price': fields.float('Price', required=True),
+ 'new_price': fields.float('Price', required=True,
+ help="If cost price is increased, stock variation account will be debited "
+ "and stock output account will be credited with the value = (difference of amount * quantity available).\n"
+ "If cost price is decreased, stock variation account will be creadited and stock input account will be debited."),
'stock_account_input':fields.many2one('account.account', 'Stock Input Account'),
'stock_account_output':fields.many2one('account.account', 'Stock Output Account'),
'stock_journal':fields.many2one('account.journal', 'Stock journal', required=True),
diff --git a/addons/stock/wizard/stock_change_standard_price_view.xml b/addons/stock/wizard/stock_change_standard_price_view.xml
index 374a34b4b6a..b46829b1a0a 100644
--- a/addons/stock/wizard/stock_change_standard_price_view.xml
+++ b/addons/stock/wizard/stock_change_standard_price_view.xml
@@ -7,7 +7,9 @@
form
-
-
+
diff --git a/addons/stock/wizard/stock_partial_picking.py b/addons/stock/wizard/stock_partial_picking.py
index 4083785a8d1..5cad3807ab3 100644
--- a/addons/stock/wizard/stock_partial_picking.py
+++ b/addons/stock/wizard/stock_partial_picking.py
@@ -48,6 +48,8 @@ class stock_partial_picking(osv.osv_memory):
self._columns['move%s_product_qty'%(m.id)] = fields.float("Quantity")
if 'move%s_product_uom'%(m.id) not in self._columns:
self._columns['move%s_product_uom'%(m.id)] = fields.many2one('product.uom',string="Product UOM")
+ if 'move%s_prodlot_id'%(m.id) not in self._columns:
+ self._columns['move%s_prodlot_id'%(m.id)] = fields.many2one('stock.production.lot', string="Lot")
if (m.product_id.cost_method == 'average'):
if 'move%s_product_price'%(m.id) not in self._columns:
@@ -62,8 +64,9 @@ class stock_partial_picking(osv.osv_memory):
picking_ids = context.get('active_ids', False)
_moves_arch_lst = """
-
-
+
+
+
"""
_moves_fields = result['fields']
@@ -91,6 +94,12 @@ class stock_partial_picking(osv.osv_memory):
'relation': 'product.uom',
'required' : True,
'readonly' : True,
+ },
+ 'move%s_prodlot_id'%(m.id): {
+ 'string': _('Production Lot'),
+ 'type': 'many2one',
+ 'relation': 'stock.production.lot',
+ 'readonly': True,
}
})
@@ -99,7 +108,8 @@ class stock_partial_picking(osv.osv_memory):
- """%(m.id, m.id, m.id)
+
+ """%(m.id, m.id, m.id, m.id)
if (m.product_id.cost_method == 'average'):
_moves_fields.update({
'move%s_product_price'%(m.id) : {
@@ -161,6 +171,8 @@ class stock_partial_picking(osv.osv_memory):
res['move%s_product_qty'%(m.id)] = m.product_qty
if 'move%s_product_uom'%(m.id) in fields:
res['move%s_product_uom'%(m.id)] = m.product_uom.id
+ if 'move%s_prodlot_id'%(m.id) in fields:
+ res['move%s_prodlot_id'%(m.id)] = m.prodlot_id.id
if (m.product_id.cost_method == 'average'):
currency = False
@@ -203,7 +215,8 @@ class stock_partial_picking(osv.osv_memory):
partial_datas['move%s'%(m.id)] = {
'product_id' : getattr(partial, 'move%s_product_id'%(m.id)).id,
'product_qty' : getattr(partial, 'move%s_product_qty'%(m.id)),
- 'product_uom' : getattr(partial, 'move%s_product_uom'%(m.id)).id
+ 'product_uom' : getattr(partial, 'move%s_product_uom'%(m.id)).id,
+ 'prodlot_id' : getattr(partial, 'move%s_prodlot_id'%(m.id)).id
}
if (m.product_id.cost_method == 'average'):
diff --git a/addons/stock_planning/__init__.py b/addons/stock_planning/__init__.py
index f0fea471a21..9873817f0f3 100644
--- a/addons/stock_planning/__init__.py
+++ b/addons/stock_planning/__init__.py
@@ -1,7 +1,8 @@
+# -*- coding: utf-8 -*-
##############################################################################
-#
+#
# OpenERP, Open Source Management Solution
-# Copyright (C) 2004-2009 Tiny SPRL ().
+# Copyright (C) 2004-2010 Tiny SPRL ().
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
@@ -14,11 +15,12 @@
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
-# along with this program. If not, see .
+# along with this program. If not, see .
#
##############################################################################
import stock_planning
+import wizard
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
diff --git a/addons/stock_planning/__openerp__.py b/addons/stock_planning/__openerp__.py
index c03945785a1..10e461acdf0 100644
--- a/addons/stock_planning/__openerp__.py
+++ b/addons/stock_planning/__openerp__.py
@@ -1,7 +1,8 @@
+# -*- coding: utf-8 -*-
##############################################################################
-#
+#
# OpenERP, Open Source Management Solution
-# Copyright (C) 2004-2009 Tiny SPRL ().
+# Copyright (C) 2004-2010 Tiny SPRL ().
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
@@ -14,7 +15,7 @@
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
-# along with this program. If not, see .
+# along with this program. If not, see .
#
##############################################################################
@@ -138,7 +139,14 @@ Remarks:
- When you wish to work with different periods for some part of products define two kinds of periods (fe. Weekly and Monthly) and use them for different products. Example: If you use always Weekly periods for Products A, and Monthly periods for Products B your all calculations will work correctly. You can also use different kind of periods for the same products from different warehouse or companies. But you cannot use overlapping periods for the same product, warehouse and company because results can be unpredictable. The same apply to Forecasts lines.
""",
"demo_xml":[],
- "update_xml":["security/ir.model.access.csv","stock_planning_view.xml"],
+ "update_xml": [
+ "security/ir.model.access.csv",
+ "stock_planning_view.xml",
+ "wizard/stock_planning_create_periods_view.xml",
+ "wizard/stock_planning_forecast_view.xml",
+ "wizard/stock_planning_createlines_view.xml",
+ ],
+ "test": ["test/stock_planning.yml"],
"active": False,
"installable": True,
}
diff --git a/addons/stock_planning/stock_planning.py b/addons/stock_planning/stock_planning.py
index e86d0fdd731..2e4f333b840 100644
--- a/addons/stock_planning/stock_planning.py
+++ b/addons/stock_planning/stock_planning.py
@@ -1,21 +1,20 @@
-# -*- encoding: utf-8 -*-
+# -*- coding: utf-8 -*-
##############################################################################
#
# OpenERP, Open Source Management Solution
-# Copyright (C) 2004-2008 Tiny SPRL (). All Rights Reserved
-# $Id$
+# Copyright (C) 2004-2010 Tiny SPRL ().
#
# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
+# it under the terms of the GNU Affero General Public License as
+# published by the Free Software Foundation, either version 3 of the
+# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
+# GNU Affero General Public License for more details.
#
-# You should have received a copy of the GNU General Public License
+# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see .
#
##############################################################################
@@ -27,7 +26,7 @@ from mx.DateTime import RelativeDateTime, now, DateTime, localtime
from osv import osv, fields
import netsvc
from tools.translate import _
-from tools import config
+#from tools import config
def rounding(fl, round_value):
@@ -35,85 +34,6 @@ def rounding(fl, round_value):
return fl
return round(fl / round_value) * round_value
-# Object creating periods quickly
-# changed that stop_date is created with hour 23:59:00 when it was 00:00:00 stop date was excluded from period
-class stock_period_createlines(osv.osv_memory):
- _name = "stock.period.createlines"
-
- def _get_new_period_start(self, cr, uid, context=None):
- cr.execute("select max(date_stop) from stock_period")
- result = cr.fetchone()
- last_date = result and result[0] or False
- if last_date:
- period_start = mx.DateTime.strptime(last_date,"%Y-%m-%d %H:%M:%S")+ RelativeDateTime(days=1)
- period_start = period_start - RelativeDateTime(hours=period_start.hour, minutes=period_start.minute, seconds=period_start.second)
- else:
- period_start = mx.DateTime.today()
- return period_start.strftime('%Y-%m-%d')
-
-
- _columns = {
- 'name': fields.char('Period Name', size=64),
- 'date_start': fields.date('Start Date', required=True),
- 'date_stop': fields.date('End Date', required=True),
- 'period_ids': fields.one2many('stock.period', 'planning_id', 'Periods'),
- }
- _defaults={
- 'date_start': _get_new_period_start,
- }
-
- def create_period_weekly(self, cr, uid, ids, context=None):
- res = self.create_period(cr, uid, ids, context, 6, 'Weekly')
- return {
- 'view_type': 'form',
- "view_mode": 'tree',
- 'res_model': 'stock.period',
- 'type': 'ir.actions.act_window',
- }
-
- def create_period_monthly(self,cr, uid, ids, interval=1, context=None):
- for p in self.browse(cr, uid, ids, context=context):
- dt = p.date_start
- ds = mx.DateTime.strptime(p.date_start, '%Y-%m-%d')
- while ds.strftime('%Y-%m-%d') < p.date_stop:
- de = ds + RelativeDateTime(months=interval, minutes=-1)
- self.pool.get('stock.period').create(cr, uid, {
- 'name': ds.strftime('%Y/%m'),
- 'date_start': ds.strftime('%Y-%m-%d'),
- 'date_stop': de.strftime('%Y-%m-%d %H:%M:%S'),
- })
- ds = ds + RelativeDateTime(months=interval)
- return {
- 'view_type': 'form',
- "view_mode": 'tree',
- 'res_model': 'stock.period',
- 'type': 'ir.actions.act_window',
- }
-
- def create_period(self, cr, uid, ids, interval=0, name='Daily', context=None):
- for p in self.browse(cr, uid, ids, context=context):
- dt = p.date_start
- ds = mx.DateTime.strptime(p.date_start, '%Y-%m-%d')
- while ds.strftime('%Y-%m-%d') < p.date_stop:
- de = ds + RelativeDateTime(days=interval, minutes =-1)
- if name =='Daily':
- new_name=de.strftime('%Y-%m-%d')
- if name =="Weekly":
- new_name = de.strftime('%Y, week %W')
- self.pool.get('stock.period').create(cr, uid, {
- 'name': new_name,
- 'date_start': ds.strftime('%Y-%m-%d'),
- 'date_stop': de.strftime('%Y-%m-%d %H:%M:%S'),
- })
- ds = ds + RelativeDateTime(days=interval) + 1
- return {
- 'view_type': 'form',
- "view_mode": 'tree',
- 'res_model': 'stock.period',
- 'type': 'ir.actions.act_window',
- }
-stock_period_createlines()
-
# Periods have no company_id field as they can be shared across similar companies.
# If somone thinks different it can be improved.
class stock_period(osv.osv):
@@ -131,104 +51,6 @@ class stock_period(osv.osv):
stock_period()
-# Creates forecasts records for products from selected Product Category for selected 'Warehouse - Period'
-# Object added by contributor in ver 1.1
-class stock_sale_forecast_createlines(osv.osv_memory):
- _name = "stock.sale.forecast.createlines"
- _description = "stock.sale.forecast.createlines"
-
-# FIXME Add some period sugestion like below
-
-# def _get_latest_period(self,cr,uid,context={}):
-# cr.execute("select max(date_stop) from stock_period")
-# result=cr.fetchone()
-# return result and result[0] or False
-
-
- _columns = {
- 'company_id': fields.many2one('res.company', 'Company', required=True, select=1),
- 'warehouse_id1': fields.many2one('stock.warehouse' , 'Warehouse', required=True, \
- help='Warehouse which forecasts will concern. '\
- 'If during stock planning you will need sales forecast for all warehouses choose any warehouse now.'),
- 'period_id1': fields.many2one('stock.period' , 'Period', required=True, help = 'Period which forecasts will concern.' ),
- 'product_categ_id1': fields.many2one('product.category' , 'Product Category', required=True, \
- help ='Product Category of products which created forecasts will concern.'),
- 'copy_forecast': fields.boolean('Copy Last Forecast', help="Copy quantities from last Stock and Sale Forecast."),
- }
-
- _defaults = {
- 'company_id': lambda self, cr, uid, c: self.pool.get('res.company')._company_default_get(cr, uid, 'stock.sale.forecast.createlines', context=c),
- }
-
- def create_forecast(self, cr, uid, ids, context=None):
- product_obj = self.pool.get('product.product')
- forecast_obj = self.pool.get('stock.sale.forecast')
- mod_obj = self.pool.get('ir.model.data')
- prod_categ_obj = self.pool.get('product.category')
- template_obj = self.pool.get('product.template')
- for f in self.browse(cr, uid, ids, context=context):
- categ_ids = f.product_categ_id1.id and [f.product_categ_id1.id] or []
- prod_categ_ids = prod_categ_obj.search(cr, uid, [('parent_id','child_of', categ_ids)])
- templates_ids = template_obj.search(cr, uid, [('categ_id','in',prod_categ_ids)])
- products_ids = product_obj.search(cr, uid, [('product_tmpl_id','in',templates_ids)])
- if len(products_ids) == 0:
- raise osv.except_osv(_('Error !'), _('No products in selected category !'))
- copy = f.copy_forecast
- for p in product_obj.browse(cr, uid, products_ids,{}):
- if len(forecast_obj.search(cr, uid, [('product_id','=',p.id) , \
- ('period_id','=',f.period_id1.id), \
- ('user_id','=',uid), \
- ('warehouse_id','=',f.warehouse_id1.id)]))== 0:
- forecast_qty = 0.0
-# Not sure if it is expected quantity for this feature (copying forecast from previous period)
-# because it can take incidental forecast of this warehouse, this product and this user (creating, writing or validating forecast).
-# It takes only one forecast line (no sum). If user creates only one forecast per period it will be OK. If not I have no idea how to count it.
-
- prod_uom = False
- if copy:
- cr.execute("SELECT period.date_stop, forecast.product_qty, forecast.product_uom \
- FROM stock_sale_forecast AS forecast \
- LEFT JOIN stock_period AS period \
- ON forecast.period_id = period.id \
- WHERE (forecast.user_id = %s OR forecast.create_uid = %s OR forecast.write_uid = %s) \
- AND forecast.warehouse_id = %s AND forecast.product_id = %s \
- AND period.date_stop < %s \
- ORDER BY period.date_stop DESC",
- (uid, uid, uid, f.warehouse_id1.id, p.id, f.period_id1.date_stop) )
- ret = cr.fetchone()
- if ret:
- forecast_qty = ret[1]
- prod_uom = ret[2]
- prod_uom = prod_uom or p.uom_id.id
- prod_uos_categ = False
- if p.uos_id:
- prod_uos_categ = p.uos_id.category_id.id
- forecast_obj.create(cr, uid, {
- 'company_id': f.warehouse_id1.company_id.id,
- 'period_id': f.period_id1.id,
- 'warehouse_id': f.warehouse_id1.id,
- 'product_id': p.id,
- 'product_qty': forecast_qty,
- 'product_amt': 0.0,
- 'product_uom': prod_uom,
- 'active_uom': prod_uom,
- 'product_uom_categ': p.uom_id.category_id.id,
- 'product_uos_categ': prod_uos_categ,
- })
- result = mod_obj._get_id(cr, uid, 'stock_planning', 'view_stock_sale_forecast_filter')
- id = mod_obj.read(cr, uid, result, ['res_id'], context=context)
-
- return {
- 'view_type': 'form',
- "view_mode": 'tree',
- 'res_model': 'stock.sale.forecast',
- 'type': 'ir.actions.act_window',
- 'search_view_id': id['res_id'],
- }
-
-stock_sale_forecast_createlines()
-
-
# Stock and Sales Forecast object. Previously stock_planning_sale_prevision.
# A lot of changes in 1.1
class stock_sale_forecast(osv.osv):
@@ -476,124 +298,6 @@ class stock_sale_forecast(osv.osv):
stock_sale_forecast()
-# Creates stock planning records for products from selected Product Category for selected 'Warehouse - Period'
-# Object added by contributor in ver 1.1
-class stock_planning_createlines(osv.osv_memory):
- _name = "stock.planning.createlines"
-
- def onchange_company(self, cr, uid, ids, company_id=False):
- result = {}
- if company_id:
- result['warehouse_id2'] = False
- return {'value': result}
-
- _columns = {
- 'company_id': fields.many2one('res.company', 'Company', required=True),
- 'period_id2': fields.many2one('stock.period' , 'Period', required=True, help = 'Period which planning will concern.'),
- 'warehouse_id2': fields.many2one('stock.warehouse' , 'Warehouse', required=True, help = 'Warehouse which planning will concern.'),
- 'product_categ_id2': fields.many2one('product.category' , 'Product Category', \
- help = 'Planning will be created for products from Product Category selected by this field. '\
- 'This field is ignored when you check \"All Forecasted Product\" box.' ),
- 'forecasted_products': fields.boolean('All Products with Forecast', \
- help = "Check this box to create planning for all products having any forecast for selected Warehouse and Period. "\
- "Product Category field will be ignored."),
- }
-
- _defaults = {
- 'company_id': lambda self, cr, uid, c: self.pool.get('res.company')._company_default_get(cr, uid, 'stock.planning', context=c),
- }
-
- def create_planning(self,cr, uid, ids, context=None):
- if context is None:
- context = {}
- product_obj = self.pool.get('product.product')
- planning_obj = self.pool.get('stock.planning')
- mod_obj = self.pool.get('ir.model.data')
- for f in self.browse(cr, uid, ids, context=context):
- if f.forecasted_products:
- cr.execute("SELECT product_id \
- FROM stock_sale_forecast \
- WHERE (period_id = %s) AND (warehouse_id = %s)", (f.period_id2.id, f.warehouse_id2.id))
- products_id1 = [x for x, in cr.fetchall()]
- else:
- prod_categ_obj = self.pool.get('product.category')
- template_obj = self.pool.get('product.template')
- categ_ids = f.product_categ_id2.id and [f.product_categ_id2.id] or []
- prod_categ_ids = prod_categ_obj.search(cr,uid,[('parent_id','child_of',categ_ids)])
- templates_ids = template_obj.search(cr,uid,[('categ_id','in',prod_categ_ids)])
- products_id1 = product_obj.search(cr,uid,[('product_tmpl_id','in',templates_ids)])
- if len(products_id1)==0:
- raise osv.except_osv(_('Error !'), _('No forecasts for selected period or no products in selected category !'))
-
- for p in product_obj.browse(cr, uid, products_id1,context=context):
- if len(planning_obj.search(cr, uid, [('product_id','=',p.id),
- ('period_id','=',f.period_id2.id),
- ('warehouse_id','=',f.warehouse_id2.id)]))== 0:
- cr.execute("SELECT period.date_stop, planning.product_uom, planning.planned_outgoing, planning.to_procure, \
- planning.stock_only, planning.procure_to_stock, planning.confirmed_forecasts_only, \
- planning.supply_warehouse_id, planning.stock_supply_location \
- FROM stock_planning AS planning \
- LEFT JOIN stock_period AS period \
- ON planning.period_id = period.id \
- WHERE (planning.create_uid = %s OR planning.write_uid = %s) \
- AND planning.warehouse_id = %s AND planning.product_id = %s \
- AND period.date_stop < %s \
- ORDER BY period.date_stop DESC",
- (uid, uid, f.warehouse_id2.id, p.id, f.period_id2.date_stop) )
- ret=cr.fetchone()
-# forecast_qty = ret and ret[0] or 0.0
- if ret:
-# raise osv.except_osv(_('Error !'), _('ret is %s %s %s %s %s %s')%(ret[0],ret[2],ret[3],ret[4],ret[5],ret[6],))
- prod_uom = ret[1]
- planned_out = ret[2]
- to_procure = ret[3]
- stock_only = ret[4]
- procure_to_stock = ret[5]
- confirmed_forecasts_only = ret[6]
- supply_warehouse_id = ret[7]
- stock_supply_location = ret[8]
- else:
- prod_uom = p.uom_id.id
- planned_out = False
- to_procure = False
- stock_only = False
- procure_to_stock = False
- confirmed_forecasts_only = False
- supply_warehouse_id = False
- stock_supply_location = False
- prod_uos_categ = False
- if p.uos_id:
- prod_uos_categ = p.uos_id.category_id.id
- planning_obj.create(cr, uid, {
- 'company_id' : f.warehouse_id2.company_id.id,
- 'period_id': f.period_id2.id,
- 'warehouse_id' : f.warehouse_id2.id,
- 'product_id': p.id,
- 'product_uom' : prod_uom,
- 'product_uom_categ' : p.uom_id.category_id.id,
- 'product_uos_categ' : prod_uos_categ,
- 'active_uom' : prod_uom,
- 'planned_outgoing': planned_out,
- 'to_procure': to_procure,
- 'stock_only': stock_only,
- 'procure_to_stock': procure_to_stock,
- 'confirmed_forecasts_only': confirmed_forecasts_only,
- 'supply_warehouse_id': supply_warehouse_id,
- 'stock_supply_location': stock_supply_location,
-
- })
- result = mod_obj._get_id(cr, uid, 'stock_planning', 'view_stock_planning_filter')
- id = mod_obj.read(cr, uid, result, ['res_id'], context=context)
- return {
- 'view_type': 'form',
- "view_mode": 'tree',
- 'res_model': 'stock.planning',
- 'type': 'ir.actions.act_window',
- 'search_view_id': id['res_id'],
- }
-stock_planning_createlines()
-
-
# The main Stock Planning object
# A lot of changes by contributor in ver 1.1
class stock_planning(osv.osv):
diff --git a/addons/stock_planning/stock_planning_view.xml b/addons/stock_planning/stock_planning_view.xml
index 0bb9222df35..10297a8ef81 100644
--- a/addons/stock_planning/stock_planning_view.xml
+++ b/addons/stock_planning/stock_planning_view.xml
@@ -1,47 +1,11 @@
-
+
-
-
-
- stock.period.createlines.form
- stock.period.createlines
- form
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Stock and Sales Planning Periods
- stock.period.createlines
- form
- form
-
- new
-
-
-
-
-
+
stock.period.form
@@ -78,53 +42,12 @@
tree,form
-
-
-
-
- stock.sale.forecast.createlines
- stock.sale.forecast.createlines
- form
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Create Sales Forecasts
- stock.sale.forecast.createlines
- form
- form
-
- new
-
-
-
-
-
stock.sale.forecast.formstock.sale.forecast
@@ -132,7 +55,7 @@
-
-
-
-
- Create Stock Planning Lines
- stock.planning.createlines
- form
- form
-
- new
-
-
-
-
-
-
stock.planning.formstock.planning
@@ -330,14 +214,13 @@
-
-
-
+
+
@@ -346,8 +229,6 @@
-
-
@@ -415,7 +296,6 @@
tree
-
@@ -423,6 +303,7 @@
+
diff --git a/addons/stock_planning/test/stock_planning.yml b/addons/stock_planning/test/stock_planning.yml
new file mode 100644
index 00000000000..178c361a10c
--- /dev/null
+++ b/addons/stock_planning/test/stock_planning.yml
@@ -0,0 +1,150 @@
+-
+ In order to test the flow of stock planning module. I will create forecast periods,
+ stock forecast and then with master procurement schedule.
+-
+ I create weekly stock periods for the month of July.
+-
+ I create stock period for the first week of July.
+-
+ !record {model: stock.period, id: stock_period_01}:
+ date_start: '2010-07-01 00:00:00'
+ date_stop: '2010/07/06 23:59:00'
+ name: 2010, week 27
+-
+ I create stock period for the second week of July.
+-
+ !record {model: stock.period, id: stock_period_02}:
+ date_start: '2010/07/07 00:00:00'
+ date_stop: '2010/07/12 23:59:00'
+ name: 2010, week 28
+-
+ I create stock period for the third week of July.
+-
+ !record {model: stock.period, id: stock_period_03}:
+ date_start: '2010/07/15 00:00:00'
+ date_stop: '2010/07/20 23:59:00'
+ name: 2010, week 29
+-
+ I create stock period for the fourth week of July.
+-
+ !record {model: stock.period, id: stock_period_04}:
+ date_start: '2010/07/22 00:00:00'
+ date_stop: '2010/07/27 23:59:00'
+ name: 2010, week 30
+-
+ I create stock period for the fifth week of July.
+-
+ !record {model: stock.period, id: stock_period_05}:
+ date_start: '2010/07/29 00:00:00'
+ date_stop: '2010/07/31 23:59:00'
+ name: 2010, week 31
+-
+ Now I create the forecast for this period for all PCs.
+-
+ !record {model: stock.sale.forecast.createlines, id: stock_sale_forecast_createlines_0}:
+ company_id: base.main_company
+ period_id: stock_period_03
+ product_categ_id: product.product_category_pc
+ warehouse_id: stock.warehouse0
+-
+ Performing an osv_memory action create_forecast on module stock.sale.forecast.createlines
+-
+ !python {model: stock.sale.forecast.createlines}: |
+ self.create_forecast(cr, uid, [ref("stock_sale_forecast_createlines_0")], {"lang":
+ 'en_US', "active_model": "ir.ui.menu", "active_ids": [ref("stock_planning.menu_stock_sale_forecast_createlines")],
+ "tz": False, "active_id": ref("stock_planning.menu_stock_sale_forecast_createlines"),
+ })
+-
+ I create a sale order for PC1-Basic PC and PC3-Medium PC.
+-
+ !record {model: sale.order, id: sale_order_so0}:
+ date_order: '2010-07-20'
+ invoice_quantity: order
+ name: SO006
+ order_line:
+ - name: '[PC1] Basic PC'
+ price_unit: 450.0
+ product_uom: product.product_uom_unit
+ product_uom_qty: 13.0
+ state: draft
+ delay: 2.0
+ product_id: product.product_product_pc1
+ product_uos_qty: 13.0
+ th_weight: 0.0
+ type: make_to_stock
+ - name: '[PC3] Medium PC'
+ price_unit: 900.0
+ product_uom: product.product_uom_unit
+ product_uom_qty: 5.0
+ state: draft
+ delay: 3.0
+ product_id: product.product_product_pc3
+ product_uos_qty: 5.0
+ th_weight: 0.0
+ type: make_to_stock
+ order_policy: manual
+ partner_id: base.res_partner_desertic_hispafuentes
+ partner_invoice_id: base.res_partner_address_3000
+ partner_order_id: base.res_partner_address_3000
+ partner_shipping_id: base.res_partner_address_3000
+ picking_policy: direct
+ pricelist_id: product.list0
+ shop_id: sale.shop
+-
+ Now I want to calculate sales history for both the products PC1-Basic PC and PC3-Medium PC and forecast the quantity.
+-
+ !python {model: stock.sale.forecast}: |
+ forecast_ids = self.search(cr, uid, [('product_id','=',ref('product.product_product_pc1'))])
+ write_dict = {'product_qty': 30.0,
+ 'analyzed_dept_id': ref("hr.dep_sales"),
+ 'analyzed_period1_id': ref("stock_period_03"),
+ 'analyzed_user_id': ref("base.user_root"),
+ 'analyzed_warehouse_id': ref("stock.warehouse0")}
+ self.write(cr, uid, forecast_ids, write_dict)
+ self.calculate_sales_history(cr, uid, forecast_ids, {"lang": "en_US", "tz":
+ False, "search_default_create_uid": 1, "active_model": "ir.ui.menu", "department_id":
+ False, "active_ids": [ref("stock_planning.menu_stock_sale_forecast_all")], "active_id":
+ ref("stock_planning.menu_stock_sale_forecast_all"), })
+-
+ I create Master procurement schedule for the third week of July.
+-
+ !record {model: stock.planning.createlines, id: stock_planning_createlines_0}:
+ company_id: base.main_company
+ period_id: stock_period_03
+ product_categ_id: product.product_category_pc
+ warehouse_id: stock.warehouse0
+-
+ Performing an osv_memory action create_planning on module stock.planning.createlines
+-
+ !python {model: stock.planning.createlines}: |
+ self.create_planning(cr, uid, [ref("stock_planning_createlines_0")], {"lang":
+ "en_US", "tz": False, "active_model": "ir.ui.menu", "active_ids": [ref("stock_planning.menu_stock_planning_createlines")],
+ "active_id": ref("stock_planning.menu_stock_planning_createlines"), "department_id":
+ False, })
+-
+ I calculate the planning in master procurement schedule.
+-
+ !python {model: stock.planning}: |
+ planning_ids = self.search(cr, uid, [('product_id','=',ref('product.product_product_pc1')),('period_id','=',ref('stock_period_03'))])
+ self.write(cr, uid, planning_ids, {'to_procure': 30.0,'planned_outgoing': 40.0})
+ self.calculate_planning(cr, uid, planning_ids, {"lang": "en_US", "tz": False,
+ "active_model": "ir.ui.menu", "active_ids": [ref("stock_planning.menu_stock_planning")],
+ "active_id": ref("stock_planning.menu_stock_planning"), "department_id": False,
+ })
+-
+ I create a procurement order for the incoming products left.
+-
+ !python {model: stock.planning}: |
+ planning_ids = self.search(cr, uid, [('product_id','=',ref('product.product_product_pc1')),('period_id','=',ref('stock_period_03'))])
+ plann = self.browse(cr, uid, planning_ids)
+ assert plann[0].incoming_left, 'Incoming Left must be greater than 0 !'
+ self.procure_incomming_left(cr, uid, planning_ids, {"lang": 'en_US', "tz":
+ False, "active_model": "ir.ui.menu", "active_ids": [ref("stock_planning.menu_stock_planning")],
+ "active_id": ref("stock_planning.menu_stock_planning"), "department_id": False,
+ })
+-
+ I check whether the procurement orders are created or not.
+-
+ !python {model: procurement.order}: |
+ proc_ids = self.search(cr, uid, [('origin','=','MPS(admin) 2010, week 29'),('product_id','=',ref("product.product_product_pc1"))])
+ assert proc_ids,'No Procurements!'
diff --git a/addons/profile_manufacturing/__init__.py b/addons/stock_planning/wizard/__init__.py
similarity index 89%
rename from addons/profile_manufacturing/__init__.py
rename to addons/stock_planning/wizard/__init__.py
index d9a31f5fb06..1e9d74d0394 100644
--- a/addons/profile_manufacturing/__init__.py
+++ b/addons/stock_planning/wizard/__init__.py
@@ -1,6 +1,6 @@
# -*- coding: utf-8 -*-
##############################################################################
-#
+#
# OpenERP, Open Source Management Solution
# Copyright (C) 2004-2010 Tiny SPRL ().
#
@@ -15,10 +15,10 @@
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
-# along with this program. If not, see .
+# along with this program. If not, see .
#
##############################################################################
-import profile_manufacturing
-
-# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
+import stock_planning_create_periods
+import stock_planning_forecast
+import stock_planning_createlines
diff --git a/addons/stock_planning/wizard/stock_planning_create_periods.py b/addons/stock_planning/wizard/stock_planning_create_periods.py
new file mode 100644
index 00000000000..fe953806dcc
--- /dev/null
+++ b/addons/stock_planning/wizard/stock_planning_create_periods.py
@@ -0,0 +1,102 @@
+# -*- coding: utf-8 -*-
+##############################################################################
+#
+# OpenERP, Open Source Management Solution
+# Copyright (C) 2004-2010 Tiny SPRL ().
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as
+# published by the Free Software Foundation, either version 3 of the
+# License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see .
+#
+##############################################################################
+
+import time
+import mx.DateTime
+from mx.DateTime import RelativeDateTime, now, DateTime, localtime
+
+from osv import osv, fields
+
+# Object creating periods quickly
+# changed that stop_date is created with hour 23:59:00 when it was 00:00:00 stop date was excluded from period
+class stock_period_createlines(osv.osv_memory):
+ _name = "stock.period.createlines"
+
+ def _get_new_period_start(self, cr, uid, context=None):
+ cr.execute("select max(date_stop) from stock_period")
+ result = cr.fetchone()
+ last_date = result and result[0] or False
+ if last_date:
+ period_start = mx.DateTime.strptime(last_date,"%Y-%m-%d %H:%M:%S")+ RelativeDateTime(days=1)
+ period_start = period_start - RelativeDateTime(hours=period_start.hour, minutes=period_start.minute, seconds=period_start.second)
+ else:
+ period_start = mx.DateTime.today()
+ return period_start.strftime('%Y-%m-%d')
+
+
+ _columns = {
+ 'name': fields.char('Period Name', size=64),
+ 'date_start': fields.date('Start Date', required=True),
+ 'date_stop': fields.date('End Date', required=True),
+ 'period_ids': fields.one2many('stock.period', 'planning_id', 'Periods'),
+ }
+ _defaults={
+ 'date_start': _get_new_period_start,
+ }
+
+ def create_stock_periods(self, cr, uid, ids, context=None):
+ interval = context.get('interval',0)
+ name = context.get('name','Daily')
+ period_obj = self.pool.get('stock.period')
+ lines = []
+ for p in self.browse(cr, uid, ids, context=context):
+ dt = p.date_start
+ ds = mx.DateTime.strptime(p.date_start, '%Y-%m-%d')
+ while ds.strftime('%Y-%m-%d') < p.date_stop:
+ if name =='Daily':
+ de = ds + RelativeDateTime(days=interval, minutes =-1)
+ new_name = de.strftime('%Y-%m-%d')
+ new_id = period_obj.create(cr, uid, {
+ 'name': new_name,
+ 'date_start': ds.strftime('%Y-%m-%d'),
+ 'date_stop': de.strftime('%Y-%m-%d %H:%M:%S'),
+ })
+ ds = ds + RelativeDateTime(days=interval) + 1
+ if name =="Weekly":
+ de = ds + RelativeDateTime(days=interval, minutes =-1)
+ new_name = de.strftime('%Y, week %W')
+ new_id = period_obj.create(cr, uid, {
+ 'name': new_name,
+ 'date_start': ds.strftime('%Y-%m-%d'),
+ 'date_stop': de.strftime('%Y-%m-%d %H:%M:%S'),
+ })
+ ds = ds + RelativeDateTime(days=interval) + 1
+ if name == "Monthly":
+ de = ds + RelativeDateTime(months=interval, minutes=-1)
+ new_name = ds.strftime('%Y/%m')
+ new_id =period_obj.create(cr, uid, {
+ 'name': new_name,
+ 'date_start': ds.strftime('%Y-%m-%d'),
+ 'date_stop': de.strftime('%Y-%m-%d %H:%M:%S'),
+ })
+ ds = ds + RelativeDateTime(months=interval)
+ lines.append(new_id)
+ return {
+ 'domain': "[('id','in', ["+','.join(map(str, lines))+"])]",
+ 'view_type': 'form',
+ "view_mode": 'tree, form',
+ 'res_model': 'stock.period',
+ 'type': 'ir.actions.act_window',
+ }
+
+stock_period_createlines()
+
+# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
diff --git a/addons/stock_planning/wizard/stock_planning_create_periods_view.xml b/addons/stock_planning/wizard/stock_planning_create_periods_view.xml
new file mode 100644
index 00000000000..4d0f9ae6a82
--- /dev/null
+++ b/addons/stock_planning/wizard/stock_planning_create_periods_view.xml
@@ -0,0 +1,40 @@
+
+
+
+
+
+
+ stock.period.createlines.form
+ stock.period.createlines
+ form
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Stock and Sales Planning Periods
+ stock.period.createlines
+ form
+ form
+
+ new
+
+
+
+
+
diff --git a/addons/stock_planning/wizard/stock_planning_createlines.py b/addons/stock_planning/wizard/stock_planning_createlines.py
new file mode 100644
index 00000000000..a0aa1e85249
--- /dev/null
+++ b/addons/stock_planning/wizard/stock_planning_createlines.py
@@ -0,0 +1,146 @@
+# -*- coding: utf-8 -*-
+##############################################################################
+#
+# OpenERP, Open Source Management Solution
+# Copyright (C) 2004-2010 Tiny SPRL ().
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as
+# published by the Free Software Foundation, either version 3 of the
+# License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see .
+#
+##############################################################################
+
+from osv import osv, fields
+from tools.translate import _
+
+# Creates stock planning records for products from selected Product Category for selected 'Warehouse - Period'
+# Object added by contributor in ver 1.1
+class stock_planning_createlines(osv.osv_memory):
+ _name = "stock.planning.createlines"
+
+ def onchange_company(self, cr, uid, ids, company_id=False):
+ result = {}
+ if company_id:
+ result['warehouse_id'] = False
+ return {'value': result}
+
+ _columns = {
+ 'company_id': fields.many2one('res.company', 'Company', required=True),
+ 'period_id': fields.many2one('stock.period' , 'Period', required=True, help = 'Period which planning will concern.'),
+ 'warehouse_id': fields.many2one('stock.warehouse' , 'Warehouse', required=True, help = 'Warehouse which planning will concern.'),
+ 'product_categ_id': fields.many2one('product.category' , 'Product Category', \
+ help = 'Planning will be created for products from Product Category selected by this field. '\
+ 'This field is ignored when you check \"All Forecasted Product\" box.' ),
+ 'forecasted_products': fields.boolean('All Products with Forecast', \
+ help = "Check this box to create planning for all products having any forecast for selected Warehouse and Period. "\
+ "Product Category field will be ignored."),
+ }
+
+ _defaults = {
+ 'company_id': lambda self, cr, uid, c: self.pool.get('res.company')._company_default_get(cr, uid, 'stock.planning', context=c),
+ }
+
+ def create_planning(self,cr, uid, ids, context=None):
+ if context is None:
+ context = {}
+ product_obj = self.pool.get('product.product')
+ planning_obj = self.pool.get('stock.planning')
+ mod_obj = self.pool.get('ir.model.data')
+ prod_categ_obj = self.pool.get('product.category')
+ template_obj = self.pool.get('product.template')
+ planning_lines = []
+ for f in self.browse(cr, uid, ids, context=context):
+ if f.forecasted_products:
+ cr.execute("SELECT product_id \
+ FROM stock_sale_forecast \
+ WHERE (period_id = %s) AND (warehouse_id = %s)", (f.period_id2.id, f.warehouse_id2.id))
+ products_id1 = [x for x, in cr.fetchall()]
+ else:
+ categ_ids = f.product_categ_id.id and [f.product_categ_id.id] or []
+ prod_categ_ids = prod_categ_obj.search(cr,uid,[('parent_id','child_of',categ_ids)])
+ templates_ids = template_obj.search(cr,uid,[('categ_id','in',prod_categ_ids)])
+ products_id1 = product_obj.search(cr,uid,[('product_tmpl_id','in',templates_ids)])
+ if len(products_id1)==0:
+ raise osv.except_osv(_('Error !'), _('No forecasts for selected period or no products in selected category !'))
+
+ for p in product_obj.browse(cr, uid, products_id1,context=context):
+ if len(planning_obj.search(cr, uid, [('product_id','=',p.id),
+ ('period_id','=',f.period_id.id),
+ ('warehouse_id','=',f.warehouse_id.id)]))== 0:
+ cr.execute("SELECT period.date_stop, planning.product_uom, planning.planned_outgoing, planning.to_procure, \
+ planning.stock_only, planning.procure_to_stock, planning.confirmed_forecasts_only, \
+ planning.supply_warehouse_id, planning.stock_supply_location \
+ FROM stock_planning AS planning \
+ LEFT JOIN stock_period AS period \
+ ON planning.period_id = period.id \
+ WHERE (planning.create_uid = %s OR planning.write_uid = %s) \
+ AND planning.warehouse_id = %s AND planning.product_id = %s \
+ AND period.date_stop < %s \
+ ORDER BY period.date_stop DESC",
+ (uid, uid, f.warehouse_id.id, p.id, f.period_id.date_stop) )
+ ret=cr.fetchone()
+# forecast_qty = ret and ret[0] or 0.0
+ if ret:
+# raise osv.except_osv(_('Error !'), _('ret is %s %s %s %s %s %s')%(ret[0],ret[2],ret[3],ret[4],ret[5],ret[6],))
+ prod_uom = ret[1]
+ planned_out = ret[2]
+ to_procure = ret[3]
+ stock_only = ret[4]
+ procure_to_stock = ret[5]
+ confirmed_forecasts_only = ret[6]
+ supply_warehouse_id = ret[7]
+ stock_supply_location = ret[8]
+ else:
+ prod_uom = p.uom_id.id
+ planned_out = False
+ to_procure = False
+ stock_only = False
+ procure_to_stock = False
+ confirmed_forecasts_only = False
+ supply_warehouse_id = False
+ stock_supply_location = False
+ prod_uos_categ = False
+ if p.uos_id:
+ prod_uos_categ = p.uos_id.category_id.id
+ planning_lines.append(planning_obj.create(cr, uid, {
+ 'company_id' : f.warehouse_id.company_id.id,
+ 'period_id': f.period_id.id,
+ 'warehouse_id' : f.warehouse_id.id,
+ 'product_id': p.id,
+ 'product_uom' : prod_uom,
+ 'product_uom_categ' : p.uom_id.category_id.id,
+ 'product_uos_categ' : prod_uos_categ,
+ 'active_uom' : prod_uom,
+ 'planned_outgoing': planned_out,
+ 'to_procure': to_procure,
+ 'stock_only': stock_only,
+ 'procure_to_stock': procure_to_stock,
+ 'confirmed_forecasts_only': confirmed_forecasts_only,
+ 'supply_warehouse_id': supply_warehouse_id,
+ 'stock_supply_location': stock_supply_location,
+
+ }))
+ result = mod_obj._get_id(cr, uid, 'stock_planning', 'view_stock_planning_filter')
+ id = mod_obj.read(cr, uid, result, ['res_id'], context=context)
+
+ return {
+ 'domain': "[('id','in', ["+','.join(map(str, planning_lines))+"])]",
+ 'view_type': 'form',
+ "view_mode": 'tree, form',
+ 'res_model': 'stock.planning',
+ 'type': 'ir.actions.act_window',
+ 'search_view_id': id['res_id'],
+ }
+
+stock_planning_createlines()
+
+# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
diff --git a/addons/stock_planning/wizard/stock_planning_createlines_view.xml b/addons/stock_planning/wizard/stock_planning_createlines_view.xml
new file mode 100644
index 00000000000..7dc4504daef
--- /dev/null
+++ b/addons/stock_planning/wizard/stock_planning_createlines_view.xml
@@ -0,0 +1,44 @@
+
+
+
+
+
+
+
+ stock.planning.createlines.form
+ stock.planning.createlines
+ form
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Create Stock Planning Lines
+ stock.planning.createlines
+ form
+ form
+
+ new
+
+
+
+
+
diff --git a/addons/stock_planning/wizard/stock_planning_forecast.py b/addons/stock_planning/wizard/stock_planning_forecast.py
new file mode 100644
index 00000000000..b261d8ffc72
--- /dev/null
+++ b/addons/stock_planning/wizard/stock_planning_forecast.py
@@ -0,0 +1,123 @@
+# -*- coding: utf-8 -*-
+##############################################################################
+#
+# OpenERP, Open Source Management Solution
+# Copyright (C) 2004-2010 Tiny SPRL ().
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as
+# published by the Free Software Foundation, either version 3 of the
+# License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see .
+#
+##############################################################################
+
+from osv import osv, fields
+
+# Creates forecasts records for products from selected Product Category for selected 'Warehouse - Period'
+# Object added by contributor in ver 1.1
+class stock_sale_forecast_createlines(osv.osv_memory):
+ _name = "stock.sale.forecast.createlines"
+ _description = "stock.sale.forecast.createlines"
+
+# FIXME Add some period sugestion like below
+
+# def _get_latest_period(self,cr,uid,context={}):
+# cr.execute("select max(date_stop) from stock_period")
+# result=cr.fetchone()
+# return result and result[0] or False
+
+
+ _columns = {
+ 'company_id': fields.many2one('res.company', 'Company', required=True, select=1),
+ 'warehouse_id': fields.many2one('stock.warehouse' , 'Warehouse', required=True, \
+ help='Warehouse which forecasts will concern. '\
+ 'If during stock planning you will need sales forecast for all warehouses choose any warehouse now.'),
+ 'period_id': fields.many2one('stock.period' , 'Period', required=True, help = 'Period which forecasts will concern.' ),
+ 'product_categ_id': fields.many2one('product.category' , 'Product Category', required=True, \
+ help ='Product Category of products which created forecasts will concern.'),
+ 'copy_forecast': fields.boolean('Copy Last Forecast', help="Copy quantities from last Stock and Sale Forecast."),
+ }
+
+ _defaults = {
+ 'company_id': lambda self, cr, uid, c: self.pool.get('res.company')._company_default_get(cr, uid, 'stock.sale.forecast.createlines', context=c),
+ }
+
+ def create_forecast(self, cr, uid, ids, context=None):
+ product_obj = self.pool.get('product.product')
+ forecast_obj = self.pool.get('stock.sale.forecast')
+ mod_obj = self.pool.get('ir.model.data')
+ prod_categ_obj = self.pool.get('product.category')
+ template_obj = self.pool.get('product.template')
+ forecast_lines = []
+ for f in self.browse(cr, uid, ids, context=context):
+ categ_ids = f.product_categ_id.id and [f.product_categ_id.id] or []
+ prod_categ_ids = prod_categ_obj.search(cr, uid, [('parent_id','child_of', categ_ids)])
+ templates_ids = template_obj.search(cr, uid, [('categ_id','in',prod_categ_ids)])
+ products_ids = product_obj.search(cr, uid, [('product_tmpl_id','in',templates_ids)])
+ if len(products_ids) == 0:
+ raise osv.except_osv(_('Error !'), _('No products in selected category !'))
+ copy = f.copy_forecast
+ for p in product_obj.browse(cr, uid, products_ids,{}):
+ if len(forecast_obj.search(cr, uid, [('product_id','=',p.id) , \
+ ('period_id','=',f.period_id.id), \
+ ('user_id','=',uid), \
+ ('warehouse_id','=',f.warehouse_id.id)]))== 0:
+ forecast_qty = 0.0
+# Not sure if it is expected quantity for this feature (copying forecast from previous period)
+# because it can take incidental forecast of this warehouse, this product and this user (creating, writing or validating forecast).
+# It takes only one forecast line (no sum). If user creates only one forecast per period it will be OK. If not I have no idea how to count it.
+
+ prod_uom = False
+ if copy:
+ cr.execute("SELECT period.date_stop, forecast.product_qty, forecast.product_uom \
+ FROM stock_sale_forecast AS forecast \
+ LEFT JOIN stock_period AS period \
+ ON forecast.period_id = period.id \
+ WHERE (forecast.user_id = %s OR forecast.create_uid = %s OR forecast.write_uid = %s) \
+ AND forecast.warehouse_id = %s AND forecast.product_id = %s \
+ AND period.date_stop < %s \
+ ORDER BY period.date_stop DESC",
+ (uid, uid, uid, f.warehouse_id.id, p.id, f.period_id.date_stop) )
+ ret = cr.fetchone()
+ if ret:
+ forecast_qty = ret[1]
+ prod_uom = ret[2]
+ prod_uom = prod_uom or p.uom_id.id
+ prod_uos_categ = False
+ if p.uos_id:
+ prod_uos_categ = p.uos_id.category_id.id
+ forecast_lines.append(forecast_obj.create(cr, uid, {
+ 'company_id': f.warehouse_id.company_id.id,
+ 'period_id': f.period_id.id,
+ 'warehouse_id': f.warehouse_id.id,
+ 'product_id': p.id,
+ 'product_qty': forecast_qty,
+ 'product_amt': 0.0,
+ 'product_uom': prod_uom,
+ 'active_uom': prod_uom,
+ 'product_uom_categ': p.uom_id.category_id.id,
+ 'product_uos_categ': prod_uos_categ,
+ }))
+ result = mod_obj._get_id(cr, uid, 'stock_planning', 'view_stock_sale_forecast_filter')
+ id = mod_obj.read(cr, uid, result, ['res_id'], context=context)
+
+ return {
+ 'domain': "[('id','in', ["+','.join(map(str, forecast_lines))+"])]",
+ 'view_type': 'form',
+ "view_mode": 'tree, form',
+ 'res_model': 'stock.sale.forecast',
+ 'type': 'ir.actions.act_window',
+ 'search_view_id': id['res_id'],
+ }
+
+stock_sale_forecast_createlines()
+
+# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
diff --git a/addons/stock_planning/wizard/stock_planning_forecast_view.xml b/addons/stock_planning/wizard/stock_planning_forecast_view.xml
new file mode 100644
index 00000000000..9b87b5cdffd
--- /dev/null
+++ b/addons/stock_planning/wizard/stock_planning_forecast_view.xml
@@ -0,0 +1,45 @@
+
+
+
+
+
+
+
+ stock.sale.forecast.createlines
+ stock.sale.forecast.createlines
+ form
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Create Sales Forecasts
+ stock.sale.forecast.createlines
+ form
+ form
+
+ new
+
+
+
+
+
+
+
+