[MERGE] merge from dev3

bzr revid: ara@tinyerp.com-20110117124103-zmjdbyc4x05w8fw1
This commit is contained in:
ARA (OpenERP) 2011-01-17 18:11:03 +05:30
commit d639116333
52 changed files with 563 additions and 374 deletions

View File

@ -1130,7 +1130,7 @@ class account_move(osv.osv):
'to_check': fields.boolean('To Review', help='Check this box if you are unsure of that journal entry and if you want to note it as \'to be reviewed\' by an accounting expert.'),
'partner_id': fields.related('line_id', 'partner_id', type="many2one", relation="res.partner", string="Partner", store=True),
'amount': fields.function(_amount_compute, method=True, string='Amount', digits_compute=dp.get_precision('Account'), type='float', fnct_search=_search_amount),
'date': fields.date('Date', required=True, states={'posted':[('readonly',True)]}),
'date': fields.date('Date', required=True, states={'posted':[('readonly',True)]}, select=True),
'narration':fields.text('Narration'),
'company_id': fields.related('journal_id','company_id',type='many2one',relation='res.company',string='Company', store=True, readonly=True),
}

View File

@ -494,12 +494,12 @@ class account_move_line(osv.osv):
'journal_id': fields.many2one('account.journal', 'Journal', required=True, select=1),
'blocked': fields.boolean('Litigation', help="You can check this box to mark this journal item as a litigation with the associated partner"),
'partner_id': fields.many2one('res.partner', 'Partner', select=1, ondelete='restrict'),
'date_maturity': fields.date('Due date', help="This field is used for payable and receivable journal entries. You can put the limit date for the payment of this line."),
'date': fields.related('move_id','date', string='Effective date', type='date', required=True,
'date_maturity': fields.date('Due date', select=True ,help="This field is used for payable and receivable journal entries. You can put the limit date for the payment of this line."),
'date': fields.related('move_id','date', string='Effective date', type='date', required=True, select=True,
store = {
'account.move': (_get_move_lines, ['date'], 20)
}),
'date_created': fields.date('Creation date'),
'date_created': fields.date('Creation date', select=True),
'analytic_lines': fields.one2many('account.analytic.line', 'move_id', 'Analytic lines'),
'centralisation': fields.selection([('normal','Normal'),('credit','Credit Centralisation'),('debit','Debit Centralisation')], 'Centralisation', size=6),
'balance': fields.function(_balance, fnct_search=_balance_search, method=True, string='Balance'),

View File

@ -211,8 +211,8 @@ class account_invoice(osv.osv):
\n* The \'Open\' state is used when user create invoice,a invoice number is generated.Its in open state till user does not pay invoice. \
\n* The \'Paid\' state is set automatically when invoice is paid.\
\n* The \'Cancelled\' state is used when user cancel invoice.'),
'date_invoice': fields.date('Invoice Date', states={'paid':[('readonly',True)], 'open':[('readonly',True)], 'close':[('readonly',True)]}, help="Keep empty to use the current date"),
'date_due': fields.date('Due Date', states={'paid':[('readonly',True)], 'open':[('readonly',True)], 'close':[('readonly',True)]},
'date_invoice': fields.date('Invoice Date', states={'paid':[('readonly',True)], 'open':[('readonly',True)], 'close':[('readonly',True)]}, select=True, help="Keep empty to use the current date"),
'date_due': fields.date('Due Date', states={'paid':[('readonly',True)], 'open':[('readonly',True)], 'close':[('readonly',True)]}, select=True,
help="If you use payment terms, the due date will be computed automatically at the generation "\
"of accounting entries. If you keep the payment term and the due date empty, it means direct payment. The payment term may compute several due dates, for example 50% now, 50% in one month."),
'partner_id': fields.many2one('res.partner', 'Partner', change_default=True, readonly=True, required=True, states={'draft':[('readonly',False)]}),

View File

@ -628,7 +628,7 @@ class account_analytic_account_summary_month(osv.osv):
tools.sql.drop_view_if_exists(cr, 'account_analytic_analysis_summary_month')
cr.execute('CREATE VIEW account_analytic_analysis_summary_month AS (' \
'SELECT ' \
'(TO_NUMBER(TO_CHAR(d.month, \'YYYYMM\'), \'999999\') + (d.account_id * 1000000))::integer AS id, ' \
'(TO_NUMBER(TO_CHAR(d.month, \'YYYYMM\'), \'999999\') + (d.account_id * 1000000::bigint))::bigint AS id, ' \
'd.account_id AS account_id, ' \
'TO_CHAR(d.month, \'Mon YYYY\') AS month, ' \
'TO_NUMBER(TO_CHAR(d.month, \'YYYYMM\'), \'999999\') AS month_id, ' \

View File

@ -54,7 +54,7 @@ class account_move_line(osv.osv):
_inherit = 'account.move.line'
_columns = {
'followup_line_id': fields.many2one('account_followup.followup.line', 'Follow-up Level'),
'followup_date': fields.date('Latest Follow-up'),
'followup_date': fields.date('Latest Follow-up', select=True),
}
account_move_line()

View File

@ -181,7 +181,7 @@ class account_voucher(osv.osv):
('receipt','Receipt'),
],'Default Type', readonly=True, states={'draft':[('readonly',False)]}),
'name':fields.char('Memo', size=256, readonly=True, states={'draft':[('readonly',False)]}),
'date':fields.date('Date', readonly=True, states={'draft':[('readonly',False)]}, help="Effective date for accounting entries"),
'date':fields.date('Date', readonly=True, select=True, states={'draft':[('readonly',False)]}, help="Effective date for accounting entries"),
'journal_id':fields.many2one('account.journal', 'Journal', required=True, readonly=True, states={'draft':[('readonly',False)]}),
'account_id':fields.many2one('account.account', 'Account', required=True, readonly=True, states={'draft':[('readonly',False)]}),
'line_ids':fields.one2many('account.voucher.line','voucher_id','Voucher Lines', readonly=True, states={'draft':[('readonly',False)]}),
@ -218,7 +218,7 @@ class account_voucher(osv.osv):
],'Payment', select=True, readonly=True, states={'draft':[('readonly',False)]}),
'tax_id':fields.many2one('account.tax', 'Tax', readonly=True, states={'draft':[('readonly',False)]}),
'pre_line':fields.boolean('Previous Payments ?', required=False),
'date_due': fields.date('Due Date', readonly=True, states={'draft':[('readonly',False)]}),
'date_due': fields.date('Due Date', readonly=True, select=True, states={'draft':[('readonly',False)]}),
'payment_option':fields.selection([
('without_writeoff', 'Keep Open'),
('with_writeoff', 'Reconcile with Write-Off'),

View File

@ -60,7 +60,7 @@ class account_analytic_account(osv.osv):
return res
where_date = ''
where_clause_args = [tuple(child_ids)]
where_clause_args = [tuple(child_ids)]
if context.get('from_date', False):
where_date += " AND l.date >= %s"
where_clause_args += [context['from_date']]
@ -71,20 +71,20 @@ class account_analytic_account(osv.osv):
SELECT a.id,
sum(
CASE WHEN l.amount > 0
THEN l.amount
THEN l.amount
ELSE 0.0
END
) as debit,
sum(
CASE WHEN l.amount < 0
THEN -l.amount
ELSE 0.0
ELSE 0.0
END
) as credit,
COALESCE(SUM(l.amount),0) AS balance,
COALESCE(SUM(l.unit_amount),0) AS quantity
FROM account_analytic_account a
LEFT JOIN account_analytic_line l ON (a.id = l.account_id)
FROM account_analytic_account a
LEFT JOIN account_analytic_line l ON (a.id = l.account_id)
WHERE a.id IN %s
""" + where_date + """
GROUP BY a.id""", where_clause_args)
@ -128,7 +128,7 @@ class account_analytic_account(osv.osv):
'contact_id': fields.many2one('res.partner.address', 'Contact'),
'user_id': fields.many2one('res.users', 'Account Manager'),
'date_start': fields.date('Date Start'),
'date': fields.date('Date End'),
'date': fields.date('Date End', select=True),
'company_id': fields.many2one('res.company', 'Company', required=False), #not required because we want to allow different companies to use the same chart of account, except for leaf accounts.
'state': fields.selection([('draft','Draft'),('open','Open'), ('pending','Pending'),('cancelled', 'Cancelled'),('close','Closed'),('template', 'Template')], 'State', required=True,
help='* When an account is created its in \'Draft\' state.\
@ -230,7 +230,7 @@ class account_analytic_line(osv.osv):
_columns = {
'name': fields.char('Description', size=256, required=True),
'date': fields.date('Date', required=True, select=1),
'date': fields.date('Date', required=True, select=True),
'amount': fields.float('Amount', required=True, help='Calculated by multiplying the quantity and the price given in the Product\'s cost price. Always expressed in the company main currency.', digits_compute=dp.get_precision('Account')),
'unit_amount': fields.float('Quantity', help='Specifies the amount of quantity to count.'),
'account_id': fields.many2one('account.analytic.account', 'Analytic Account', required=True, ondelete='cascade', select=True, domain=[('type','<>','view')]),

View File

@ -96,6 +96,8 @@ def _record_objects(self, cr, uid, data, context):
if '_auto' in dir(obj_pool):
if not obj_pool._auto:
continue
elif '_log_access' not in dir(obj_pool):
search_condition = []
search_ids=obj_pool.search(cr,uid,search_condition)
for s_id in search_ids:
args=(cr.dbname,uid,obj_name,'copy',s_id,{},context)

View File

@ -23,33 +23,15 @@ from osv import fields, osv
from tools.translate import _
from tools import ustr
class report_creator(osv.osv):
class report_result(osv.osv):
"""
Report Creator
"""
_name = "base_report_creator.report"
_name = "base_report_creator_report.result"
_description = "Report"
model_set_id = False
#
# Should request only used fields
#
def export_data(self, cr, uid, ids, fields_to_export, context=None):
if context is None:
context = {}
data_l = self.read(cr, uid, ids, ['sql_query'], context=context)
final_datas = []
#start Loop
for record in data_l:
datas = []
for key in fields_to_export:
value = record.get(key,'')
if isinstance(value, tuple):
datas.append(ustr(value[1]))
else:
datas.append(ustr(value))
final_datas += [datas]
#End Loop
return {'datas': final_datas}
def fields_get(self, cr, user, fields=None, context=None):
"""
@ -64,9 +46,9 @@ class report_creator(osv.osv):
data = context and context.get('report_id', False) or False
if (not context) or 'report_id' not in context:
return super(report_creator, self).fields_get(cr, user, fields, context)
return super(report_result, self).fields_get(cr, user, fields, context)
if data:
report = self.browse(cr, user, data)
report = self.pool.get('base_report_creator.report').browse(cr, user, data,context=context)
models = {}
#Start Loop
for model in report.model_ids:
@ -80,12 +62,8 @@ class report_creator(osv.osv):
i += 1
else:
fields['column_count'] = {'readonly': True, 'type': 'integer', 'string': 'Count', 'size': 64, 'name': 'column_count'}
return fields
#
# Should Call self.fields_get !
#
def fields_view_get(self, cr, user, view_id=None, view_type='form', context=None, toolbar=False, submenu=False):
"""
Overrides orm field_view_get.
@ -98,8 +76,8 @@ class report_creator(osv.osv):
data = context and context.get('report_id', False) or False
if (not context) or 'report_id' not in context:
return super(report_creator, self).fields_view_get(cr, user, view_id, view_type, context, toolbar=toolbar, submenu=submenu)
report = self.browse(cr, user, data)
return super(report_result, self).fields_view_get(cr, user, view_id, view_type, context, toolbar=toolbar, submenu=submenu)
report = self.pool.get('base_report_creator.report').browse(cr, user, context.get('report_id'), context=context)
models = {}
for model in report.model_ids:
models[model.model] = self.pool.get(model.model).fields_get(cr, user, context=context)
@ -192,31 +170,11 @@ class report_creator(osv.osv):
"""
if context is None:
context = {}
data = context.get('report_id', False)
res = super(report_creator, self).read(cr, user, ids, fields, context, load)
if (not context) or 'report_id' not in context:
return res
wp = ''
for data in res:
if not data.get('sql_query'):
return res
if self.model_set_id:
wp = [self._id_get(cr, user, data, context) + (' in (%s)' % (','.join(map(lambda x: "'" + str(x) + "'", ids))))]
cr.execute(data['sql_query'])
res = cr.dictfetchall()
fields_get = self.fields_get(cr, user, None, context)
for r in res:
for k in r:
r[k] = r[k] or False
field_dict = fields_get.get(k)
field_type = field_dict and field_dict.get('type', False) or False
if field_type and field_type == 'many2one':
if r[k] == False:
continue
related_name = self.pool.get(field_dict.get('relation')).name_get(cr, user, [r[k]], context)[0]
r[k] = related_name
return res
report_id = context.get('active_id', False)
report = self.pool.get('base_report_creator.report').browse(cr, user, context.get('report_id'), context=context)
cr.execute(report.sql_query)
result = cr.dictfetchall()
return result
def search(self, cr, user, args, offset=0, limit=None, order=None, context=None, count=False):
"""
@ -231,9 +189,9 @@ class report_creator(osv.osv):
context_id = context.get('report_id', False)
if (not context) or 'report_id' not in context:
return super(report_creator, self).search(cr, user, args, offset, limit, order, context, count)
return {}
if context_id:
report = self.browse(cr, user, context_id)
report = self.pool.get('base_report_creator.report').browse(cr, user, context_id, context=context)
i = 0
fields = {}
for f in report.field_ids:
@ -254,10 +212,42 @@ class report_creator(osv.osv):
ctx = context or {}
ctx['getid'] = True
sql_query = report.sql_query
cr.execute(sql_query, newargs2)
cr.execute(sql_query) # TODO: FILTER
result = cr.fetchall()
return map(lambda x: x[0], result)
report_result()
class report_creator(osv.osv):
"""
Report Creator
"""
_name = "base_report_creator.report"
_description = "Report"
model_set_id = False
#
# Should request only used fields
#
def export_data(self, cr, uid, ids, fields_to_export, context=None):
if context is None:
context = {}
data_l = self.read(cr, uid, ids, ['sql_query'], context=context)
final_datas = []
#start Loop
for record in data_l:
datas = []
for key in fields_to_export:
value = record.get(key,'')
if isinstance(value, tuple):
datas.append(ustr(value[1]))
else:
datas.append(ustr(value))
final_datas += [datas]
#End Loop
return {'datas': final_datas}
def _path_get(self, cr, uid, models, filter_ids=[]):
"""
@param cr: the current row, from the database cursor,
@ -465,7 +455,7 @@ class report_creator(osv.osv):
'name': rep.name,
'view_type': 'form',
'view_mode': view_mode,
'res_model': 'base_report_creator.report',
'res_model': 'base_report_creator_report.result',
'type': 'ir.actions.act_window',
'context': "{'report_id':%d}" % (rep.id,),
'nodestroy': True,
@ -596,3 +586,4 @@ class report_creator_filter(osv.osv):
}
report_creator_filter()
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

View File

@ -41,7 +41,7 @@ appropriate staff, and make sure all future correspondence gets to the right
place.
The CRM module has a email gateway for the synchronisation interface
between mails and OpenERP.
between mails and OpenERP.
Create dashboard for CRM that includes:
* My Leads (list)
* Leads by Stage (graph)
@ -95,6 +95,7 @@ Create dashboard for CRM that includes:
'crm_meeting_view.xml',
'crm_meeting_menu.xml',
'crm_meeting_shortcut_data.xml',
'crm_phonecall_view.xml',
'crm_phonecall_menu.xml',
@ -106,12 +107,12 @@ Create dashboard for CRM that includes:
'report/crm_phonecall_report_view.xml',
'process/crm_configuration_process.xml',
'crm_installer_view.xml',
'crm_installer_view.xml',
'res_partner_view.xml',
'board_crm_view.xml',
'board_crm_statistical_view.xml',
],
'demo_xml': [
'crm_demo.xml',

View File

@ -92,12 +92,6 @@
action="crm_case_categ_meet" parent="menu_meeting_sale"
sequence="1" />
<record id="ir_ui_view_sc_calendar0" model="ir.ui.view_sc">
<field name="name">Meetings</field>
<field name="resource">ir.ui.menu</field>
<field name="user_id" ref="base.user_root"/>
<field name="res_id" ref="crm.menu_crm_case_categ_meet"/>
</record>
<record id="action_view_attendee_form" model="ir.actions.act_window">
<field name="name">Meeting Invitations</field>
<field name="type">ir.actions.act_window</field>

View File

@ -0,0 +1,13 @@
<?xml version="1.0"?>
<openerp>
<data noupdate="1">
<record id="ir_ui_view_sc_calendar0" model="ir.ui.view_sc">
<field name="name">Meetings</field>
<field name="resource">ir.ui.menu</field>
<field name="user_id" ref="base.user_root"/>
<field name="res_id" ref="crm.menu_crm_case_categ_meet"/>
</record>
</data>
</openerp>

View File

@ -146,7 +146,7 @@ class hr_employee(osv.osv):
'marital': fields.many2one('hr.employee.marital.status', 'Marital Status'),
'department_id':fields.many2one('hr.department', 'Department'),
'address_id': fields.many2one('res.partner.address', 'Working Address'),
'address_home_id': fields.many2one('res.partner.address', 'Home Address'),
'address_home_id': fields.many2one('res.partner.address', 'Home Address', domain="[('partner_id', '!=', False)]"),
'partner_id': fields.related('address_home_id', 'partner_id', type='many2one', relation='res.partner', readonly=True, help="Partner that is related to the current employee. Accounting transaction will be written on this partner belongs to employee."),
'bank_account_id':fields.many2one('res.partner.bank', 'Bank Account', domain="[('partner_id','=',partner_id)]", help="Employee bank salary account"),
'work_phone': fields.char('Work Phone', size=32, readonly=False),

View File

@ -14,6 +14,12 @@
<field name="domain_force">[(1,'=',1)]</field>
<field name="groups" eval="[(4,ref('base.group_hr_manager'))]"/>
</record>
<record id="property_rule_attendace_employee" model="ir.rule">
<field name="name">Employee Attendance</field>
<field model="ir.model" name="model_id" ref="model_hr_attendance"/>
<field name="domain_force">[('employee_id.user_id','=',user.id)]</field>
<field name="groups" eval="[(4,ref('base.group_user'))]"/>
</record>
</data>

View File

@ -143,7 +143,7 @@ class hr_evaluation(osv.osv):
_description = "Employee Evaluation"
_rec_name = 'employee_id'
_columns = {
'date': fields.date("Evaluation Deadline", required=True),
'date': fields.date("Evaluation Deadline", required=True, select=True),
'employee_id': fields.many2one('hr.employee', "Employee", required=True),
'note_summary': fields.text('Evaluation Summary'),
'note_action': fields.text('Action Plan',
@ -165,7 +165,7 @@ class hr_evaluation(osv.osv):
('done','Done'),
('cancel','Cancelled'),
], 'State', required=True, readonly=True),
'date_close': fields.date('Ending Date'),
'date_close': fields.date('Ending Date', select=True),
'progress': fields.float("Progress"),
}
_defaults = {

View File

@ -60,12 +60,12 @@ class hr_expense_expense(osv.osv):
'name': fields.char('Description', size=128, required=True),
'id': fields.integer('Sheet ID', readonly=True),
'ref': fields.char('Reference', size=32),
'date': fields.date('Date'),
'date': fields.date('Date', select=True),
'journal_id': fields.many2one('account.journal', 'Force Journal', help = "The journal used when the expense is invoiced"),
'employee_id': fields.many2one('hr.employee', "Employee", required=True),
'user_id': fields.many2one('res.users', 'User', required=True),
'date_confirm': fields.date('Confirmation Date', help = "Date of the confirmation of the sheet expense. It's filled when the button Confirm is pressed."),
'date_valid': fields.date('Validation Date', help = "Date of the acceptation of the sheet expense. It's filled when the button Accept is pressed."),
'date_confirm': fields.date('Confirmation Date', select=True, help = "Date of the confirmation of the sheet expense. It's filled when the button Confirm is pressed."),
'date_valid': fields.date('Validation Date', select=True, help = "Date of the acceptation of the sheet expense. It's filled when the button Accept is pressed."),
'user_valid': fields.many2one('res.users', 'Validation User'),
'account_move_id': fields.many2one('account.move', 'Ledger Posting'),
'line_ids': fields.one2many('hr.expense.line', 'expense_id', 'Expense Lines', readonly=True, states={'draft':[('readonly',False)]} ),
@ -251,13 +251,17 @@ class hr_expense_line(osv.osv):
product = self.pool.get('product.product').browse(cr, uid, product_id, context=context)
res['name'] = product.name
# Compute based on pricetype of employee company
ctx['currency_id'] = self.pool.get('hr.employee').browse(cr, uid, employee_id, context=context).user_id.company_id.currency_id.id
amount_unit = product.price_get('standard_price', ctx)[product.id]
res['unit_amount'] = amount_unit
employee = self.pool.get('hr.employee').browse(cr, uid, employee_id, context=context)
if employee.user_id:
ctx['currency_id'] = self.pool.get('hr.employee').browse(cr, uid, employee_id, context=context).user_id.company_id.currency_id.id
amount_unit = product.price_get('standard_price', ctx)[product.id]
res['unit_amount'] = amount_unit
else:
res['unit_amount'] = product.standard_price
if not uom_id:
res['uom_id'] = product.uom_id.id
return {'value': res}
hr_expense_line()
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

View File

@ -14,6 +14,12 @@
<field name="domain_force">[(1,'=',1)]</field>
<field name="groups" eval="[(4,ref('base.group_hr_manager'))]"/>
</record>
<record id="property_rule_expense_employee" model="ir.rule">
<field name="name">Employee Expense</field>
<field model="ir.model" name="model_id" ref="model_hr_expense_expense"/>
<field name="domain_force">[('employee_id.user_id','=',user.id)]</field>
<field name="groups" eval="[(4,ref('base.group_user'))]"/>
</record>
</data>
</openerp>

View File

@ -14,6 +14,12 @@
<field name="domain_force">[(1,'=',1)]</field>
<field name="groups" eval="[(6,0,[ref('base.group_hr_manager')])]"/>
</record>
<record id="property_rule_holidays_employee" model="ir.rule">
<field name="name">Employee Holidays</field>
<field model="ir.model" name="model_id" ref="model_hr_holidays"/>
<field name="domain_force">[('employee_id.user_id','=',user.id)]</field>
<field name="groups" eval="[(4,ref('base.group_user'))]"/>
</record>
</data>
</openerp>

View File

@ -126,7 +126,7 @@ class hr_applicant(crm.crm_case, osv.osv):
'partner_id': fields.many2one('res.partner', 'Partner'),
'partner_address_id': fields.many2one('res.partner.address', 'Partner Contact', \
domain="[('partner_id','=',partner_id)]"),
'create_date': fields.datetime('Creation Date', readonly=True),
'create_date': fields.datetime('Creation Date', readonly=True, select=True),
'write_date': fields.datetime('Update Date', readonly=True),
'stage_id': fields.many2one ('hr.recruitment.stage', 'Stage'),
'state': fields.selection(AVAILABLE_STATES, 'State', size=16, readonly=True,
@ -137,8 +137,8 @@ class hr_applicant(crm.crm_case, osv.osv):
'company_id': fields.many2one('res.company', 'Company'),
'user_id': fields.many2one('res.users', 'Responsible'),
# Applicant Columns
'date_closed': fields.datetime('Closed', readonly=True),
'date_open': fields.datetime('Opened', readonly=True),
'date_closed': fields.datetime('Closed', readonly=True, select=True),
'date_open': fields.datetime('Opened', readonly=True, select=True),
'date': fields.datetime('Date'),
'date_action': fields.date('Next Action Date'),
'title_action': fields.char('Next Action', size=64),

View File

@ -50,7 +50,7 @@ class report_custom(report_rml):
emp_obj = pooler.get_pool(cr.dbname).get('hr.employee')
user_id = emp_obj.browse(cr, uid, emp_id).user_id.id
empl_name = emp_obj.browse(cr, uid, emp_id).name
# Computing the dates (start of month: som, and end of month: eom)
som = datetime.date(data['form']['year'], data['form']['month'], 1)
eom = som + datetime.timedelta(lengthmonth(som.year, som.month))

View File

@ -262,7 +262,7 @@ class hr_timesheet_sheet(osv.osv):
'user_id': fields.related('employee_id', 'user_id', type="many2one", relation="res.users", store=True, string="User", required=False, readonly=True),#fields.many2one('res.users', 'User', required=True, select=1, states={'confirm':[('readonly', True)], 'done':[('readonly', True)]}),
'date_from': fields.date('Date from', required=True, select=1, readonly=True, states={'new':[('readonly', False)]}),
'date_to': fields.date('Date to', required=True, select=1, readonly=True, states={'new':[('readonly', False)]}),
'date_current': fields.date('Current date', required=True),
'date_current': fields.date('Current date', required=True, select=1),
'timesheet_ids' : one2many_mod('hr.analytic.timesheet', 'sheet_id',
'Timesheet lines', domain=[('date', '=', time.strftime('%Y-%m-%d'))],
readonly=True, states={

View File

@ -342,7 +342,7 @@ class mrp_bom(osv.osv):
if context is None:
context = {}
bom_data = self.read(cr, uid, id, [], context=context)
default.update({'name': bom_data['name'] + ' ' + _('Copy')})
default.update({'name': bom_data['name'] + ' ' + _('Copy'), 'bom_id':False})
return super(mrp_bom, self).copy_data(cr, uid, id, default, context=context)
mrp_bom()
@ -444,7 +444,7 @@ class mrp_production(osv.osv):
'bom_id': fields.many2one('mrp.bom', 'Bill of Material', domain=[('bom_id','=',False)]),
'routing_id': fields.many2one('mrp.routing', string='Routing', on_delete='set null', help="The list of operations (list of work centers) to produce the finished product. The routing is mainly used to compute work center costs during operations and to plan future loads on work centers based on production plannification."),
'picking_id': fields.many2one('stock.picking', 'Picking list', readonly=True,
'picking_id': fields.many2one('stock.picking', 'Picking list', readonly=True, ondelete="restrict",
help="This is the internal picking list that brings the finished product to the production plan"),
'move_prod_id': fields.many2one('stock.move', 'Move product', readonly=True),
'move_lines': fields.many2many('stock.move', 'mrp_production_move_ids', 'production_id', 'move_id', 'Products to Consume', domain=[('state','not in', ('done', 'cancel'))], states={'done':[('readonly',True)]}),
@ -602,12 +602,18 @@ class mrp_production(osv.osv):
workcenter_line_obj.create(cr, uid, line)
return len(results)
def action_cancel(self, cr, uid, ids):
def action_cancel(self, cr, uid, ids, context=None):
""" Cancels the production order and related stock moves.
@return: True
"""
if context is None:
context = {}
move_obj = self.pool.get('stock.move')
for production in self.browse(cr, uid, ids):
for production in self.browse(cr, uid, ids, context=context):
if production.state == 'confirmed' and production.picking_id.state not in ('draft', 'cancel'):
raise osv.except_osv(
_('Could not cancel manufacturing order !'),
_('You must first cancel related internal picking attached to this manufacturing order.'))
if production.move_created_ids:
move_obj.action_cancel(cr, uid, [x.id for x in production.move_created_ids])
move_obj.action_cancel(cr, uid, [x.id for x in production.move_lines])
@ -664,7 +670,7 @@ class mrp_production(osv.osv):
"""
stock_mov_obj = self.pool.get('stock.move')
production = self.browse(cr, uid, production_id, context=context)
final_product_todo = []
produced_qty = 0
@ -708,9 +714,9 @@ class mrp_production(osv.osv):
if production_mode == 'consume_produce':
# To produce remaining qty of final product
vals = {'state':'confirmed'}
final_product_todo = [x.id for x in production.move_created_ids]
#final_product_todo = [x.id for x in production.move_created_ids]
#stock_mov_obj.write(cr, uid, final_product_todo, vals)
stock_mov_obj.action_confirm(cr, uid, final_product_todo, context)
#stock_mov_obj.action_confirm(cr, uid, final_product_todo, context)
produced_products = {}
for produced_product in production.move_created_ids2:
if produced_product.scrapped:

View File

@ -343,6 +343,54 @@
<field name="date_start"/>
<field name="date_stop"/>
</tree>
<form string="Bill of Material">
<group colspan="4" col="6">
<field name="product_id" on_change="onchange_product_id(product_id, name)" select="1"/>
<field name="name" select="1"/>
<field name="code" select="1" string="Reference" groups="base.group_extended"/>
<newline/>
<field name="product_qty"/>
<field name="product_uom"/>
<field name="routing_id" groups="base.group_extended"/>
<newline/>
<field name="product_uos_qty" groups="product.group_uos" />
<field name="product_uos" groups="product.group_uos"/>
<newline/>
<field name="type" groups="base.group_extended"/>
<field name="company_id" select="1" groups="base.group_multi_company" widget="selection"/>
</group>
<group groups="base.group_extended">
<notebook colspan="4">
<page string="Components">
<field colspan="4" name="bom_lines" nolabel="1" widget="one2many_list">
<tree string="Components" editable="bottom">
<field name="product_id" on_change="onchange_product_id(product_id, name)" select="1"/>
<field name="product_qty"/>
<field name="product_uom"/>
<field name="name" invisible="1"/>
<field name="date_start"/>
<field name="date_stop"/>
</tree>
</field>
</page>
<page string="Revisions" groups="base.group_extended" attrs="{'invisible': [('bom_id','!=',False)]}">
<field colspan="4" name="revision_ids" nolabel="1" widget="one2many_list"/>
</page>
<page string="Properties" groups="base.group_extended">
<field name="position"/>
<field name="active"/>
<field name="sequence"/>
<field name="bom_id"/>
<field name="date_start"/>
<field name="date_stop"/>
<field name="product_rounding"/>
<field name="product_efficiency" groups="base.group_extended"/>
<field colspan="4" name="property_ids" nolabel="2" groups="base.group_extended"/>
</page>
</notebook>
</group>
</form>
</field>
</page>
<page string="Revisions" groups="base.group_extended" attrs="{'invisible': [('bom_id','!=',False)]}">
@ -412,6 +460,28 @@
</tree>
</field>
</record>
<record id="mrp_bom_component_tree_view" model="ir.ui.view">
<field name="name">mrp.bom.component.tree</field>
<field name="model">mrp.bom</field>
<field name="type">tree</field>
<field name="field_parent">child_complete_ids</field>
<field name="arch" type="xml">
<tree string="BoM Structure" colors="blue:method">
<field name="sequence" invisible="1"/>
<field name="name" string="Component Name"/>
<field name="code"/>
<field name="product_id" string="Component Product"/>
<field name="bom_id"/>
<field name="product_qty"/>
<field name="product_uom"/>
<field name="type"/>
<field name="method" groups="base.group_extended"/>
<field name="routing_id" groups="base.group_extended"/>
<field name="date_start" groups="base.group_extended"/>
<field name="date_stop" groups="base.group_extended"/>
</tree>
</field>
</record>
<record id="mrp_bom_form_action" model="ir.actions.act_window">
<field name="name">Bill of Materials</field>
<field name="type">ir.actions.act_window</field>
@ -426,6 +496,7 @@
<field name="type">ir.actions.act_window</field>
<field name="res_model">mrp.bom</field>
<field name="view_type">form</field>
<field name="view_id" ref="mrp_bom_component_tree_view"/>
<field name="domain">[('bom_id','!=',False)]</field>
<field name="help">Bills of materials components are components and sub-products used to create master bills of materials. Use this menu to search in which BoM a specific component is used.</field>
</record>
@ -616,7 +687,6 @@
<field name="product_id" readonly="1"/>
<field name="product_qty" readonly="1" string="Qty"/>
<field name="product_uom" readonly="1" string="UOM"/>
<field name="location_dest_id" readonly="1" string="Destination Loc."/>
<field name="prodlot_id" context="{'product_id': product_id}"/>
<field name="state" invisible="1"/>
<field name="scrapped" invisible="1"/>
@ -630,7 +700,8 @@
<separator colspan="4"/>
<group col="9" colspan="4">
<field name="state"/>
<button name="button_cancel" states="draft,ready,confirmed,in_production,picking_except" string="Cancel" icon="gtk-stop"/>
<button name="button_cancel" states="draft,ready,in_production,picking_except" string="Cancel" icon="gtk-stop"/>
<button name="action_cancel" type="object" states="confirmed" string="Cancel" icon="gtk-stop"/>
<button name="button_confirm" states="draft" string="Confirm Production" icon="gtk-apply"/>
<button name="button_produce" states="ready" string="Start Production" icon="terp-gtk-jump-to-ltr"/>
<button name="%(act_mrp_product_produce)d" states="in_production" string="Produce" icon="gtk-ok" type="action"/>
@ -645,7 +716,6 @@
<field name="product_id" />
<field name="product_qty" string="Qty"/>
<field name="product_uom" string="UOM"/>
<field name="location_id" string="Source Loc." />
<field name="state" invisible="1"/>
<button name="%(stock.action_partial_move_server)d"
string="Partial"
@ -680,7 +750,7 @@
<button name="action_compute" states="draft"
string="Compute Data" type="object"
icon="terp-stock_format-scientific"
colspan="4" />
colspan="2" />
<field colspan="4" name="workcenter_lines" nolabel="1">
<form string="Production Work Centers">
<field colspan="4" name="name"/>
@ -702,7 +772,7 @@
<button name="action_compute" states="draft"
string="Compute Data" type="object"
icon="terp-stock_format-scientific"
colspan="4" />
colspan="2" />
<field colspan="4" name="product_lines" nolabel="1" widget="one2many_list"/>
</page>
<page string="Extra Information">

View File

@ -30,6 +30,11 @@ class StockMove(osv.osv):
_columns = {
'production_id': fields.many2one('mrp.production', 'Production', select=True),
}
def create_chained_picking(self, cr, uid, moves, context=None):
new_moves = super(StockMove, self).create_chained_picking(cr, uid, moves, context=context)
self.write(cr, uid, [x.id for x in new_moves], {'production_id': False}, context=context)
return new_moves
def _action_explode(self, cr, uid, move, context=None):
""" Explodes pickings.

View File

@ -327,6 +327,9 @@ class mrp_repair(osv.osv):
self.write(cr, uid, [o.id], {'state': '2binvoiced'})
else:
self.write(cr, uid, [o.id], {'state': 'confirmed'})
for line in o.operations:
if line.product_id.track_production and not line.prodlot_id:
raise osv.except_osv(_('Warning'), _("Production lot is required for opration line with product '%s'") % (line.product_id.name))
mrp_line_obj.write(cr, uid, [l.id for l in o.operations], {'state': 'confirmed'})
return True
@ -535,6 +538,7 @@ class mrp_repair(osv.osv):
'location_id': move.location_id.id,
'location_dest_id': move.location_dest_id.id,
'tracking_id': False,
'prodlot_id': move.prodlot_id and move.prodlot_id.id or False,
'state': 'done',
})
repair_line_obj.write(cr, uid, [move.id], {'move_id': move_id, 'state': 'done'}, context=context)
@ -661,6 +665,7 @@ class mrp_repair_line(osv.osv, ProductChangeMixin):
'tax_id': fields.many2many('account.tax', 'repair_operation_line_tax', 'repair_operation_line_id', 'tax_id', 'Taxes'),
'product_uom_qty': fields.float('Quantity (UoM)', digits=(16,2), required=True),
'product_uom': fields.many2one('product.uom', 'Product UoM', required=True),
'prodlot_id': fields.many2one('stock.production.lot', 'Lot Number',domain="[('product_id','=',product_id)]"),
'invoice_line_id': fields.many2one('account.invoice.line', 'Invoice Line', readonly=True),
'location_id': fields.many2one('stock.location', 'Source Location', required=True, select=True),
'location_dest_id': fields.many2one('stock.location', 'Dest. Location', required=True, select=True),

View File

@ -49,7 +49,8 @@
<notebook>
<page string="Repair Line">
<field name="name" colspan="4"/>
<field name="product_id" on_change="product_id_change(parent.pricelist_id,product_id,product_uom,product_uom_qty, parent.partner_id)" colspan="4"/>
<field name="product_id" on_change="product_id_change(parent.pricelist_id,product_id,product_uom,product_uom_qty, parent.partner_id)"/>
<field name='prodlot_id'/>
<field name="product_uom_qty" string="Qty" />
<field name="product_uom" string="UoM"/>
<field name="price_unit"/>
@ -178,7 +179,7 @@
<field name="arch" type="xml">
<search string="Search Reair Orders">
<group col='4' colspan='4'>
<filter icon="terp-document-new" string="Quotations" domain="[('state','=','draft')]"/>
<filter icon="terp-document-new" string="Quotations" domain="[('state','=','draft')]"/>
<filter icon="terp-check" string="Confirmed" domain="[('state','=','confirmed')]" name="current" />
<filter icon="terp-emblem-important" string="Ready To Repair" domain="[('state','=','ready')]"/>
<separator orientation="vertical"/>
@ -202,7 +203,7 @@
</field>
</record>
<record id="action_repair_order_tree" model="ir.actions.act_window">
<field name="name">Repair Orders</field>
@ -212,7 +213,7 @@
<field name="view_mode">tree,form</field>
<field name="search_view_id" ref="view_repair_order_form_filter"/>
<field name="help">Repair orders allow you to organize your product repairs. In a repair order, you can detail the components you remove, add or replace and record the time you spent on the different operations. The repair order uses the warranty date on the production lot in order to know if whether the repair should be invoiced to the customer or not.</field>
</record>
</record>
<menuitem action="action_repair_order_tree" id="menu_repair_order" parent="mrp.menu_mrp_manufacturing" groups="mrp.group_mrp_user" name="Repair Orders" sequence="50"/>

View File

@ -33,7 +33,7 @@ class pos_config_journal(osv.osv):
""" Point of Sale journal configuration"""
_name = 'pos.config.journal'
_description = "Journal Configuration"
_columns = {
'name': fields.char('Description', size=64),
'code': fields.char('Code', size=64),
@ -46,7 +46,7 @@ pos_config_journal()
class pos_company_discount(osv.osv):
""" Company Discount and Cashboxes """
_inherit = 'res.company'
_columns = {
'company_discount': fields.float('Max Discount(%)', digits_compute=dp.get_precision('Point Of Sale')),
'max_diff': fields.float('Max Difference for Cashboxes', digits_compute=dp.get_precision('Point Of Sale Discount')),
@ -247,14 +247,14 @@ class pos_order(osv.osv):
'num_sale': fields.char('Internal Note', size=64),
'shop_id': fields.many2one('sale.shop', 'Shop', required=True,
states={'draft': [('readonly', False)]}, readonly=True),
'date_order': fields.datetime('Date Ordered', readonly=True),
'date_order': fields.datetime('Date Ordered', readonly=True, select=True),
'date_validation': fields.function(_get_date_payment,
method=True,
string='Validation Date',
type='date', store=True),
type='date', select=True, store=True),
'date_payment': fields.function(_get_date_payment2, method=True,
string='Payment Date',
type='date', store=True),
type='date', select=True, store=True),
'date_validity': fields.date('Validity Date', required=True),
'user_id': fields.many2one('res.users', 'Connected Salesman', help="Person who uses the the cash register. It could be a reliever, a student or an interim employee."),
'user_salesman_id': fields.many2one('res.users', 'Cashier', required=True, help="User who is logged into the system."),
@ -332,7 +332,7 @@ class pos_order(osv.osv):
def test_order_lines(self, cr, uid, order, context=None):
""" Test order line is created or not for the order
""" Test order line is created or not for the order
@param name: Names of fields.
@return: True
"""
@ -573,9 +573,9 @@ class pos_order(osv.osv):
return statement_id
def add_product(self, cr, uid, order_id, product_id, qty, context=None):
"""Create a new order line the order"""
line_obj = self.pool.get('pos.order.line')
values = self.read(cr, uid, order_id, ['partner_id', 'pricelist_id'])
@ -596,9 +596,9 @@ class pos_order(osv.osv):
return order_line_id, price
def refund(self, cr, uid, ids, context=None):
"""Create a copy of order for refund order"""
clone_list = []
line_obj = self.pool.get('pos.order.line')
@ -623,9 +623,9 @@ class pos_order(osv.osv):
return clone_list
def action_invoice(self, cr, uid, ids, context=None):
"""Create a invoice of order """
inv_ref = self.pool.get('account.invoice')
inv_line_ref = self.pool.get('account.invoice.line')
product_obj = self.pool.get('product.product')

View File

@ -361,17 +361,22 @@ class procurement_order(osv.osv):
"""
ok = True
if procurement.move_id:
message = False
id = procurement.move_id.id
if not (procurement.move_id.state in ('done','assigned','cancel')):
ok = ok and self.pool.get('stock.move').action_assign(cr, uid, [id])
cr.execute('select count(id) from stock_warehouse_orderpoint where product_id=%s', (procurement.product_id.id,))
if not cr.fetchone()[0]:
cr.execute('update procurement_order set message=%s where id=%s',
(_('Not enough stock and no minimum orderpoint rule defined.'),
procurement.id))
message = _("Procurement '%s' is in exception: not enough stock.") % \
(procurement.name,)
self.log(cr, uid, procurement.id, message)
res = cr.fetchone()[0]
if not res and not ok:
message = _("Not enough stock and no minimum orderpoint rule defined.")
elif not res:
message = _("No minimum orderpoint rule defined.")
elif not ok:
message = _("Not enough stock.")
if message:
self.log(cr, uid, procurement.id, _("Procurement '%s' is in exception: ") % (procurement.name) + message)
cr.execute('update procurement_order set message=%s where id=%s', (message, procurement.id))
return ok
def action_produce_assign_service(self, cr, uid, ids, context=None):

View File

@ -53,6 +53,7 @@
'product_data.xml',
'product_report.xml',
'product_view.xml',
'product_shortcut_data.xml',
'pricelist_view.xml',
'partner_view.xml',
'process/product_process.xml'

View File

@ -166,10 +166,9 @@ class product_pricelist(osv.osv):
pricelist_version_ids = pricelist_ids
else:
# all pricelists:
pricelist_version_ids = product_pricelist_version_obj.search(cr, uid, [])
pricelist_version_ids = self.pool.get('product.pricelist').search(cr, uid, [], context=context)
pricelist_version_ids = list(set(pricelist_version_ids))
plversions_search_args = [
('pricelist_id', 'in', pricelist_version_ids),
'|',

View File

@ -482,6 +482,19 @@ class product_product(osv.osv):
'pricelist_id': fields.dummy(string='Pricelist', relation='product.pricelist', type='many2one'),
'name_template': fields.related('product_tmpl_id', 'name', string="Name", type='char', size=128, store=True),
}
def unlink(self, cr, uid, ids, context=None):
unlink_ids = []
unlink_product_tmpl_ids = []
for product in self.browse(cr, uid, ids, context=context):
tmpl_id = product.product_tmpl_id.id
# Check if the product is last product of this template
other_product_ids = self.search(cr, uid, [('product_tmpl_id', '=', tmpl_id), ('id', '!=', product.id)], context=context)
if not other_product_ids:
unlink_product_tmpl_ids.append(tmpl_id)
unlink_ids.append(product.id)
self.pool.get('product.template').unlink(cr, uid, unlink_product_tmpl_ids, context=context)
return super(product_product, self).unlink(cr, uid, unlink_ids, context=context)
def onchange_uom(self, cursor, user, ids, uom_id,uom_po_id):
if uom_id and uom_po_id:

View File

@ -0,0 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<openerp>
<data noupdate="1">
<record id="ir_ui_view_sc_product0" model="ir.ui.view_sc">
<field name="name">Products</field>
<field name="resource">ir.ui.menu</field>
<field name="user_id" ref="base.user_root"/>
<field name="res_id" ref="product.menu_products"/>
</record>
</data>
</openerp>

View File

@ -9,7 +9,7 @@
<field name="type">search</field>
<field name="arch" type="xml">
<search string="Product">
<filter string="Services" icon="terp-accessories-archiver" domain="[('type','=','service')]"/>
<filter string="Services" icon="terp-accessories-archiver" domain="[('type','=','service')]"/>
<filter string="Stockable" icon="terp-accessories-archiver" domain="['|',('type','=','product'),('type','=','consu')]"/>
<separator orientation="vertical"/>
<filter string="To Sell" icon="terp-accessories-archiver-minus" domain="[('sale_ok','=',1)]"/>
@ -30,7 +30,7 @@
<separator orientation="vertical"/>
<filter string='Type' icon="terp-stock_symbol-selection" domain="[]" context="{'group_by' : 'type'}" />
</group>
</search>
</field>
</record>
@ -101,7 +101,7 @@
</group>
<group colspan="2" col="2" groups="base.group_extended">
<separator string="Weigths" colspan="2"/>
<separator string="Weights" colspan="2"/>
<field digits="(14, 3)" name="volume" attrs="{'readonly':[('type','=','service')]}"/>
<field digits="(14, 3)" name="weight" attrs="{'readonly':[('type','=','service')]}"/>
<field digits="(14, 3)" name="weight_net" attrs="{'readonly':[('type','=','service')]}"/>
@ -567,7 +567,7 @@
</group>
<group colspan="2" col="2" groups="base.group_extended">
<separator string="Weigths" colspan="2"/>
<separator string="Weights" colspan="2"/>
<field digits="(14, 3)" name="volume" attrs="{'readonly':[('type','=','service')]}"/>
<field digits="(14, 3)" name="weight" attrs="{'readonly':[('type','=','service')]}"/>
<field digits="(14, 3)" name="weight_net" attrs="{'readonly':[('type','=','service')]}"/>
@ -635,12 +635,6 @@
<field name="view_type">form</field>
<field name="view_id" ref="product_template_tree_view"/>
</record>
<record id="ir_ui_view_sc_product0" model="ir.ui.view_sc">
<field name="name">Products</field>
<field name="resource">ir.ui.menu</field>
<field name="user_id" ref="base.user_root"/>
<field name="res_id" ref="product.menu_products"/>
</record>
</data>
</openerp>

View File

@ -62,18 +62,18 @@ class product_pricelist(report_sxw.rml_parse):
def _get_pricelist(self, pricelist_id):
pool = pooler.get_pool(self.cr.dbname)
pricelist = pool.get('product.pricelist').read(self.cr, self.uid, [pricelist_id], ['name'])[0]
pricelist = pool.get('product.pricelist').read(self.cr, self.uid, [pricelist_id], ['name'], context=self.localcontext)[0]
return pricelist['name']
def _get_currency(self, pricelist_id):
pool = pooler.get_pool(self.cr.dbname)
pricelist = pool.get('product.pricelist').read(self.cr, self.uid, [pricelist_id], ['currency_id'])[0]
pricelist = pool.get('product.pricelist').read(self.cr, self.uid, [pricelist_id], ['currency_id'], context=self.localcontext)[0]
return pricelist['currency_id'][1]
def _get_currency_symbol(self, pricelist_id):
pool = pooler.get_pool(self.cr.dbname)
pricelist = pool.get('product.pricelist').read(self.cr, self.uid, [pricelist_id], ['currency_id'])[0]
symbol = pool.get('res.currency').read(self.cr, self.uid, [pricelist['currency_id'][0]], ['symbol'])[0]
pricelist = pool.get('product.pricelist').read(self.cr, self.uid, [pricelist_id], ['currency_id'], context=self.localcontext)[0]
symbol = pool.get('res.currency').read(self.cr, self.uid, [pricelist['currency_id'][0]], ['symbol'], context=self.localcontext)[0]
return symbol['symbol'] or ''
def _get_categories(self, products,form):
@ -88,13 +88,13 @@ class product_pricelist(report_sxw.rml_parse):
if product.categ_id.id not in cat_ids:
cat_ids.append(product.categ_id.id)
cats = pool.get('product.category').name_get(self.cr, self.uid, cat_ids)
cats = pool.get('product.category').name_get(self.cr, self.uid, cat_ids, context=self.localcontext)
if not cats:
return res
for cat in cats:
product_ids=pool.get('product.product').search(self.cr, self.uid, [('id','in',pro_ids),('categ_id','=',cat[0])])
product_ids=pool.get('product.product').search(self.cr, self.uid, [('id', 'in', pro_ids), ('categ_id', '=', cat[0])], context=self.localcontext)
products = []
for product in pool.get('product.product').read(self.cr, self.uid, product_ids, ['name','code']):
for product in pool.get('product.product').read(self.cr, self.uid, product_ids, ['name', 'code'], context=self.localcontext):
val = {
'id':product['id'],
'name':product['name'],
@ -114,7 +114,7 @@ class product_pricelist(report_sxw.rml_parse):
def _get_price(self,pricelist_id, product_id,qty):
sale_price_digits = self.get_digits(dp='Sale Price')
pool = pooler.get_pool(self.cr.dbname)
price_dict = pool.get('product.pricelist').price_get(self.cr, self.uid, [pricelist_id], product_id,qty)
price_dict = pool.get('product.pricelist').price_get(self.cr, self.uid, [pricelist_id], product_id, qty, context=self.localcontext)
if price_dict[pricelist_id]:
price = self.formatLang(price_dict[pricelist_id], digits=sale_price_digits)
else:

View File

@ -148,7 +148,7 @@ class purchase_order(osv.osv):
STATE_SELECTION = [
('draft', 'Request for Quotation'),
('wait', 'Waiting'),
('confirmed', 'Waiting Supplier Ack'),
('confirmed', 'Waiting Approval'),
('approved', 'Approved'),
('except_picking', 'Shipping Exception'),
('except_invoice', 'Invoice Exception'),
@ -455,6 +455,7 @@ class purchase_order(osv.osv):
'state': 'draft',
'purchase_line_id': order_line.id,
'company_id': order.company_id.id,
'price_unit': order_line.price_unit
})
if order_line.move_dest_id:
self.pool.get('stock.move').write(cr, uid, [order_line.move_dest_id.id], {'location_id':order.location_id.id})
@ -816,4 +817,22 @@ class procurement_order(osv.osv):
procurement_order()
class stock_invoice_onshipping(osv.osv_memory):
_inherit = "stock.invoice.onshipping"
def create_invoice(self, cr, uid, ids, context=None):
if context is None:
context = {}
res = super(stock_invoice_onshipping,self).create_invoice(cr, uid, ids, context=context)
purchase_obj = self.pool.get('purchase.order')
picking_obj = self.pool.get('stock.picking')
for pick_id in res:
pick = picking_obj.browse(cr, uid, pick_id, context=context)
if pick.purchase_id:
purchase_obj.write(cr, uid, [pick.purchase_id.id], {
'invoice_ids': [(4, res[pick_id])]}, context=context)
return res
stock_invoice_onshipping()
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

View File

@ -5,19 +5,19 @@
<record id="base.user_demo" model="res.users">
<field eval="[(4, ref('group_purchase_user'))]" name="groups_id"/>
</record>
<!--Resource: purchase.order-->
<record id="order_purchase1" model="purchase.order">
<field name="location_id" ref="stock.stock_location_stock"/>
<field model="product.pricelist" name="pricelist_id" search="[]"/>
<field name="pricelist_id" ref="purchase.list0"/>
<field name="partner_id" ref="base.res_partner_asus"/>
<field name="partner_address_id" ref="base.res_partner_address_tang"/>
</record>
<record id="order_purchase2" model="purchase.order">
<field name="location_id" ref="stock.stock_location_stock"/>
<field model="product.pricelist" name="pricelist_id" search="[]"/>
<field name="pricelist_id" ref="purchase.list0"/>
<field name="partner_id" ref="base.res_partner_3"/>
<field name="partner_address_id" ref="base.res_partner_address_zen"/>
</record>
@ -48,7 +48,7 @@
<field name="order_id" ref="order_purchase2"/>
<field name="date_planned" eval="time.strftime('%Y/%m/%d')"/>
<field name="name">[PC3] Medium PC</field>
<field name="product_id" ref="product.product_product_pc1"/>
<field name="product_id" ref="product.product_product_pc3"/>
<field name="product_uom" ref="product.product_uom_unit"/>
<field name="price_unit">900</field>
<field name="product_qty">1</field>

View File

@ -15,7 +15,7 @@
<menuitem
id="menu_purchase_config_pricelist" name="Pricelists"
parent="menu_purchase_config_purchase" sequence="50"/>
<menuitem
action="product.product_pricelist_action" id="menu_product_pricelist_action_purhase"
parent="menu_purchase_config_pricelist" sequence="20"/>
@ -32,7 +32,7 @@
<menuitem
id="menu_product_in_config_purchase" name="Product"
parent="menu_purchase_config_purchase" sequence="30"/>
<menuitem
action="product.product_category_action_form" id="menu_product_category_config_purchase"
parent="purchase.menu_product_in_config_purchase" sequence="10"/>
@ -40,7 +40,7 @@
<menuitem
id="menu_purchase_unit_measure_purchase" name="Units of Measure"
parent="purchase.menu_product_in_config_purchase" sequence="20"/>
<menuitem
action="product.product_uom_categ_form_action" id="menu_purchase_uom_categ_form_action"
parent="menu_purchase_unit_measure_purchase" sequence="30"/>
@ -113,10 +113,10 @@
<!--product menu-->
<menuitem id="menu_procurement_management_product" name="Products"
parent="base.menu_purchase_root" sequence="8"/>
<menuitem name="Products by Category" id="menu_product_by_category_purchase_form" action="product.product_category_action"
parent="menu_procurement_management_product" sequence="10"/>
<menuitem name="Products" id="menu_procurement_partner_contact_form" action="product.product_normal_action_puchased"
parent="menu_procurement_management_product"/>
@ -194,7 +194,7 @@
<button name="invoice_ok" states="except_invoice" string="Manually Corrected" icon="gtk-convert"/>
<button name="purchase_confirm" states="draft" string="Convert to Purchase Order" icon="gtk-go-forward"/>
<button name="purchase_appbuyer" states="wait_auth" string="Approve Purchase" icon="gtk-ok"/>
<button name="purchase_approve" states="confirmed" string="Approved by Supplier" icon="gtk-go-forward"/>
<button name="purchase_approve" states="confirmed" string="Approved" icon="gtk-go-forward"/>
<button name="%(report_purchase_order)d" string="Print" states="approved" type="action" icon="gtk-print"/>
</group>
</page>
@ -292,7 +292,7 @@
<field name="search_view_id" ref="view_purchase_order_filter"/>
<field name="help">You can create a request for quotation when you want to buy products to a supplier but the purchase is not confirmed yet. Use also this menu to review requests for quotation created automatically based on your logistic rules (minimum stock, MTO, etc). You can convert the request for quotation into a purchase order once the order is confirmed. If you use the extended interface (from user's preferences), you can select the way to control your supplier invoices: based on the order, based on the receptions or manual encoding.</field>
</record>
<menuitem action="purchase_rfq" id="menu_purchase_rfq"
<menuitem action="purchase_rfq" id="menu_purchase_rfq"
parent="menu_procurement_management"
sequence="6"/>
@ -458,7 +458,7 @@
<field name="name">Purchase Lines Not Invoiced</field>
<field name="type">ir.actions.act_window</field>
<field name="res_model">purchase.order.line</field>
<field name="domain">[('state','in',('confirmed','done')), ('invoiced', '=', False)]</field>
<field name="domain">[('order_id.invoice_method','&lt;&gt;','picking'), ('state','in',('confirmed','done')), ('invoiced', '=', False)]</field>
<field name="view_type">form</field>
<field name="view_mode">tree,form</field>
<field name="search_view_id" ref="purchase_order_line_search"/>

View File

@ -171,7 +171,8 @@
</record>
<menuitem id="base.next_id_73" name="Reporting" parent="base.menu_purchase_root" sequence="8"/>
<menuitem id="base.next_id_73" name="Reporting" parent="base.menu_purchase_root" sequence="8"
groups="purchase.group_purchase_manager"/>
<menuitem action="action_purchase_order_report_all" id="menu_action_purchase_order_report_all" parent="base.next_id_73" sequence="3"/>
<record id="action_stock_move_report_po" model="ir.actions.act_window">

View File

@ -58,6 +58,19 @@ class stock_picking(osv.osv):
'purchase_id': False,
}
def _get_address_invoice(self, cr, uid, picking):
""" Gets invoice address of a partner
@return {'contact': address, 'invoice': address} for invoice
"""
res = super(stock_picking, self)._get_address_invoice(cr, uid, picking)
if picking.purchase_id:
partner_obj = self.pool.get('res.partner')
partner = picking.purchase_id.partner_id or picking.address_id.partner_id
data = partner_obj.address_get(cr, uid, [partner.id],
['contact', 'invoice'])
res.update(data)
return res
def get_currency_id(self, cursor, user, picking):
if picking.purchase_id:
return picking.purchase_id.pricelist_id.currency_id.id

View File

@ -22,7 +22,7 @@
<field name="inherit_id" ref="purchase.view_purchase_order_filter"/>
<field name="arch" type="xml">
<xpath expr="/search/group/filter[@string='Not Invoiced']" position="after">
<filter icon="terp-gtk-jump-to-rtl" string="Requisition" domain="[('requisition_id','!=',False)]" separator="1"/>
<filter icon="terp-gtk-jump-to-rtl" string="Requisition" domain="[('requisition_id','!=',False)]" separator="1" help="Purchase Orders with requisition"/>
</xpath>
</field>
</record>

View File

@ -1,7 +1,7 @@
"id","name","model_id:id","group_id:id","perm_read","perm_write","perm_create","perm_unlink"
"access_purchase_requisition","purchase.requisition","model_purchase_requisition","purchase.group_purchase_user",1,1,1,1
"access_purchase_requisition_line","purchase.requisition.line","model_purchase_requisition_line","purchase.group_purchase_user",1,1,1,1
"access_purchase_requisition_line_purchase_user","purchase.requisition.line","model_purchase_requisition_line","purchase.group_purchase_user",1,1,1,1
"access_purchase_requisition_manager","purchase.requisition manager","model_purchase_requisition","purchase.group_purchase_manager",1,0,0,0
"access_purchase_requisition_line_manager","purchase.requisition.line manager","model_purchase_requisition_line","purchase.group_purchase_manager",1,0,0,0
"access_purchase_requisition","purchase.requisition","model_purchase_requisition","stock.group_stock_manager",1,0,1,0
"access_purchase_requisition_line","purchase.requisition.line","model_purchase_requisition_line","stock.group_stock_manager",1,0,1,0
"access_purchase_requisition_stock_manager","purchase.requisition","model_purchase_requisition","stock.group_stock_manager",1,0,1,0
"access_purchase_requisition_line_stock_manager","purchase.requisition.line","model_purchase_requisition_line","stock.group_stock_manager",1,0,1,0

1 id name model_id:id group_id:id perm_read perm_write perm_create perm_unlink
2 access_purchase_requisition purchase.requisition model_purchase_requisition purchase.group_purchase_user 1 1 1 1
3 access_purchase_requisition_line access_purchase_requisition_line_purchase_user purchase.requisition.line model_purchase_requisition_line purchase.group_purchase_user 1 1 1 1
4 access_purchase_requisition_manager purchase.requisition manager model_purchase_requisition purchase.group_purchase_manager 1 0 0 0
5 access_purchase_requisition_line_manager purchase.requisition.line manager model_purchase_requisition_line purchase.group_purchase_manager 1 0 0 0
6 access_purchase_requisition access_purchase_requisition_stock_manager purchase.requisition model_purchase_requisition stock.group_stock_manager 1 0 1 0
7 access_purchase_requisition_line access_purchase_requisition_line_stock_manager purchase.requisition.line model_purchase_requisition_line stock.group_stock_manager 1 0 1 0

View File

@ -4,6 +4,9 @@
<record id="base.de" model="res.country">
<field eval="True" name="intrastat"/>
</record>
<record id="base.be" model="res.country">
<field eval="True" name="intrastat"/>
</record>
<record id="base.at" model="res.country">
<field eval="True" name="intrastat"/>
</record>

View File

@ -185,7 +185,7 @@ class sale_order(osv.osv):
for line in self.pool.get('sale.order.line').browse(cr, uid, ids, context=context):
result[line.order_id.id] = True
return result.keys()
_columns = {
'name': fields.char('Order Reference', size=64, required=True,
readonly=True, states={'draft': [('readonly', False)]}, select=True),
@ -202,9 +202,9 @@ class sale_order(osv.osv):
('done', 'Done'),
('cancel', 'Cancelled')
], 'Order State', readonly=True, help="Gives the state of the quotation or sales order. \nThe exception state is automatically set when a cancel operation occurs in the invoice validation (Invoice Exception) or in the picking list process (Shipping Exception). \nThe 'Waiting Schedule' state is set when the invoice is confirmed but waiting for the scheduler to run on the date 'Ordered Date'.", select=True),
'date_order': fields.date('Ordered Date', required=True, readonly=True, states={'draft': [('readonly', False)]}),
'create_date': fields.date('Creation Date', readonly=True, help="Date on which sales order is created."),
'date_confirm': fields.date('Confirmation Date', readonly=True, help="Date on which sales order is confirmed."),
'date_order': fields.date('Ordered Date', required=True, readonly=True, select=True, states={'draft': [('readonly', False)]}),
'create_date': fields.date('Creation Date', readonly=True, select=True, help="Date on which sales order is created."),
'date_confirm': fields.date('Confirmation Date', readonly=True, select=True, help="Date on which sales order is confirmed."),
'user_id': fields.many2one('res.users', 'Salesman', states={'draft': [('readonly', False)]}, select=True),
'partner_id': fields.many2one('res.partner', 'Customer', readonly=True, states={'draft': [('readonly', False)]}, required=True, change_default=True, select=True),
'partner_invoice_id': fields.many2one('res.partner.address', 'Invoice Address', readonly=True, required=True, states={'draft': [('readonly', False)]}, help="Invoice address for current sales order."),
@ -705,7 +705,6 @@ class sale_order(osv.osv):
#'state': 'waiting',
'note': line.notes,
'company_id': order.company_id.id,
'returned_price': line.price_unit,
})
if line.product_id:
@ -739,12 +738,13 @@ class sale_order(osv.osv):
proc_obj.write(cr, uid, [proc_id], {'product_qty': mov.product_qty, 'product_uos_qty': mov.product_uos_qty})
val = {}
for proc_id in proc_ids:
wf_service.trg_validate(uid, 'procurement.order', proc_id, 'button_confirm', cr)
if picking_id:
wf_service.trg_validate(uid, 'stock.picking', picking_id, 'button_confirm', cr)
for proc_id in proc_ids:
wf_service.trg_validate(uid, 'procurement.order', proc_id, 'button_confirm', cr)
if order.state == 'shipping_except':
val['state'] = 'progress'
val['shipped'] = False

View File

@ -172,6 +172,7 @@
<page groups="base.group_extended" string="Extra Info">
<field name="th_weight"/>
<field name="address_allotment_id"/>
<field name="property_ids" colspan="4"/>
</page>
<page string="Notes">
<field colspan="4" name="notes" nolabel="1"/>

View File

@ -106,7 +106,7 @@
<separator string="Stocks" colspan="4"/>
<field name="qty_available"/>
<button name="%(action_view_change_product_quantity)d" string="Update" attrs="{'invisible': [('type', '=', 'service')]}"
type="action" icon="gtk-execute" groups = "stock.group_stock_manager,base.group_sale_manager,purchase.group_purchase_manager,stock.group_stock_manager,mrp.group_mrp_manager"/>
type="action" icon="gtk-execute" groups = "stock.group_stock_manager,stock.group_stock_user"/>
<newline/>
<field name="virtual_available"/>
</group>

View File

@ -864,8 +864,7 @@ class stock_picking(osv.osv):
@return {'contact': address, 'invoice': address} for invoice
"""
partner_obj = self.pool.get('res.partner')
partner = (picking.purchase_id and picking.purchase_id.partner_id) or (picking.sale_id and picking.sale_id.partner_id) or picking.address_id.partner_id
partner = picking.address_id.partner_id
return partner_obj.address_get(cr, uid, [partner.id],
['contact', 'invoice'])
@ -960,6 +959,7 @@ class stock_picking(osv.osv):
invoice_obj = self.pool.get('account.invoice')
invoice_line_obj = self.pool.get('account.invoice.line')
address_obj = self.pool.get('res.partner.address')
invoices_group = {}
res = {}
inv_type = type
@ -983,6 +983,7 @@ class stock_picking(osv.osv):
address_contact_id, address_invoice_id = \
self._get_address_invoice(cr, uid, picking).values()
address = address_obj.browse(cr, uid, address_contact_id, context=context)
comment = self._get_comment_invoice(cr, uid, picking)
if group and partner.id in invoices_group:
@ -1002,7 +1003,7 @@ class stock_picking(osv.osv):
'origin': (picking.name or '') + (picking.origin and (':' + picking.origin) or ''),
'type': inv_type,
'account_id': account_id,
'partner_id': partner.id,
'partner_id': address.partner_id.id,
'address_invoice_id': address_invoice_id,
'address_contact_id': address_contact_id,
'comment': comment,
@ -1159,6 +1160,7 @@ class stock_picking(osv.osv):
complete, too_many, too_few = [], [], []
move_product_qty = {}
prodlot_ids = {}
product_avail = {}
for move in pick.move_lines:
if move.state in ('done', 'cancel'):
continue
@ -1184,6 +1186,12 @@ class stock_picking(osv.osv):
move_currency_id = move.company_id.currency_id.id
context['currency_id'] = move_currency_id
qty = uom_obj._compute_qty(cr, uid, product_uom, product_qty, product.uom_id.id)
if product.id in product_avail:
product_avail[product.id] += qty
else:
product_avail[product.id] = product.qty_available
if qty > 0:
new_price = currency_obj.compute(cr, uid, product_currency,
move_currency_id, product_price)
@ -1194,9 +1202,8 @@ class stock_picking(osv.osv):
else:
# Get the standard price
amount_unit = product.price_get('standard_price', context)[product.id]
new_std_price = ((amount_unit * product.qty_available)\
+ (new_price * qty))/(product.qty_available + qty)
new_std_price = ((amount_unit * product_avail[product.id])\
+ (new_price * qty))/(product_avail[product.id] + qty)
# Write the field according to price type field
product_obj.write(cr, uid, [product.id], {'standard_price': new_std_price})
@ -1206,8 +1213,6 @@ class stock_picking(osv.osv):
{'price_unit': product_price,
'price_currency_id': product_currency})
if not move.returned_price:
move_obj.write(cr, uid, [move.id], {'returned_price': move.price_unit})
for move in too_few:
product_qty = move_product_qty[move.id]
@ -1547,7 +1552,6 @@ class stock_move(osv.osv):
# used for colors in tree views:
'scrapped': fields.related('location_dest_id','scrap_location',type='boolean',relation='stock.location',string='Scrapped', readonly=True),
'returned_price': fields.float('Returned product price', digits_compute= dp.get_precision('Sale Price')),
}
_constraints = [
(_check_tracking,
@ -1784,7 +1788,7 @@ class stock_move(osv.osv):
picking_obj = self.pool.get('stock.picking')
pick_id= picking_obj.create(cr, uid, {
'name': pick_name,
'origin': str(picking.origin or ''),
'origin': tools.ustr(picking.origin or ''),
'type': ptype,
'note': picking.note,
'move_type': picking.move_type,
@ -1796,6 +1800,51 @@ class stock_move(osv.osv):
'date': picking.date,
})
return pick_id
def create_chained_picking(self, cr, uid, moves, context=None):
res_obj = self.pool.get('res.company')
location_obj = self.pool.get('stock.location')
move_obj = self.pool.get('stock.move')
wf_service = netsvc.LocalService("workflow")
new_moves = []
if context is None:
context = {}
seq_obj = self.pool.get('ir.sequence')
for picking, todo in self._chain_compute(cr, uid, moves, context=context).items():
ptype = todo[0][1][5] and todo[0][1][5] or location_obj.picking_type_get(cr, uid, todo[0][0].location_dest_id, todo[0][1][0])
if picking:
# name of new picking according to its type
new_pick_name = seq_obj.get(cr, uid, 'stock.picking.' + ptype)
pickid = self._create_chained_picking(cr, uid, new_pick_name, picking, ptype, todo, context=context)
# Need to check name of old picking because it always considers picking as "OUT" when created from Sale Order
old_ptype = location_obj.picking_type_get(cr, uid, picking.move_lines[0].location_id, picking.move_lines[0].location_dest_id)
if old_ptype != picking.type:
old_pick_name = seq_obj.get(cr, uid, 'stock.picking.' + old_ptype)
self.pool.get('stock.picking').write(cr, uid, picking.id, {'name': old_pick_name}, context=context)
else:
pickid = False
for move, (loc, dummy, delay, dummy, company_id, ptype) in todo:
new_id = move_obj.copy(cr, uid, move.id, {
'location_id': move.location_dest_id.id,
'location_dest_id': loc.id,
'date_moved': time.strftime('%Y-%m-%d'),
'picking_id': pickid,
'state': 'waiting',
'company_id': company_id or res_obj._company_default_get(cr, uid, 'stock.company', context=context) ,
'move_history_ids': [],
'date': (datetime.strptime(move.date, '%Y-%m-%d %H:%M:%S') + relativedelta(days=delay or 0)).strftime('%Y-%m-%d'),
'move_history_ids2': []}
)
move_obj.write(cr, uid, [move.id], {
'move_dest_id': new_id,
'move_history_ids': [(4, new_id)]
})
new_moves.append(self.browse(cr, uid, [new_id])[0])
if pickid:
wf_service.trg_validate(uid, 'stock.picking', pickid, 'button_confirm', cr)
if new_moves:
new_moves += self.create_chained_picking(cr, uid, new_moves, context)
return new_moves
def action_confirm(self, cr, uid, ids, context=None):
""" Confirms stock move.
@return: List of ids.
@ -1807,46 +1856,7 @@ class stock_move(osv.osv):
move_obj = self.pool.get('stock.move')
wf_service = netsvc.LocalService("workflow")
def create_chained_picking(self, cr, uid, moves, context=None):
new_moves = []
if context is None:
context = {}
seq_obj = self.pool.get('ir.sequence')
for picking, todo in self._chain_compute(cr, uid, moves, context=context).items():
ptype = todo[0][1][5] and todo[0][1][5] or location_obj.picking_type_get(cr, uid, todo[0][0].location_dest_id, todo[0][1][0])
if picking:
# name of new picking according to its type
new_pick_name = seq_obj.get(cr, uid, 'stock.picking.' + ptype)
pickid = self._create_chained_picking(cr, uid, new_pick_name, picking, ptype, todo, context=context)
# Need to check name of old picking because it always considers picking as "OUT" when created from Sale Order
old_ptype = location_obj.picking_type_get(cr, uid, picking.move_lines[0].location_id, picking.move_lines[0].location_dest_id)
if old_ptype != picking.type:
old_pick_name = seq_obj.get(cr, uid, 'stock.picking.' + old_ptype)
self.pool.get('stock.picking').write(cr, uid, picking.id, {'name': old_pick_name}, context=context)
else:
pickid = False
for move, (loc, dummy, delay, dummy, company_id, ptype) in todo:
new_id = move_obj.copy(cr, uid, move.id, {
'location_id': move.location_dest_id.id,
'location_dest_id': loc.id,
'date_moved': time.strftime('%Y-%m-%d'),
'picking_id': pickid,
'state': 'waiting',
'company_id': company_id or res_obj._company_default_get(cr, uid, 'stock.company', context=context) ,
'move_history_ids': [],
'date': (datetime.strptime(move.date, '%Y-%m-%d %H:%M:%S') + relativedelta(days=delay or 0)).strftime('%Y-%m-%d'),
'move_history_ids2': []}
)
move_obj.write(cr, uid, [move.id], {
'move_dest_id': new_id,
'move_history_ids': [(4, new_id)]
})
new_moves.append(self.browse(cr, uid, [new_id])[0])
if pickid:
wf_service.trg_validate(uid, 'stock.picking', pickid, 'button_confirm', cr)
if new_moves:
create_chained_picking(self, cr, uid, new_moves, context)
create_chained_picking(self, cr, uid, moves, context)
self.create_chained_picking(cr, uid, moves, context)
return []
def action_assign(self, cr, uid, ids, *args):
@ -2114,6 +2124,8 @@ class stock_move(osv.osv):
prodlot_id = partial_datas and partial_datas.get('move%s_prodlot_id' % (move.id), False)
if prodlot_id:
self.write(cr, uid, [move.id], {'prodlot_id': prodlot_id}, context=context)
if move.state not in ('confirmed','done'):
self.action_confirm(cr, uid, move_ids, context=context)
self.write(cr, uid, move_ids, {'state': 'done', 'date_planned': time.strftime('%Y-%m-%d %H:%M:%S')}, context=context)
for id in move_ids:
@ -2218,6 +2230,8 @@ class stock_move(osv.osv):
'tracking_id': move.tracking_id.id,
'prodlot_id': move.prodlot_id.id,
}
if move.location_id.usage <> 'internal':
default_val.update({'location_id': move.location_dest_id.id})
new_move = self.copy(cr, uid, move.id, default_val)
res += [new_move]
@ -2568,22 +2582,33 @@ class stock_inventory(osv.osv):
self.write(cr, uid, [inv.id], {'state': 'confirm', 'move_ids': [(6, 0, move_ids)]})
return True
def action_cancel(self, cr, uid, ids, context=None):
def action_cancel_draft(self, cr, uid, ids, context=None):
""" Cancels the stock move and change inventory state to draft.
@return: True
"""
for inv in self.browse(cr, uid, ids, context=context):
self.pool.get('stock.move').action_cancel(cr, uid, [x.id for x in inv.move_ids], context)
self.write(cr, uid, [inv.id], {'state': 'draft'})
self.pool.get('stock.move').action_cancel(cr, uid, [x.id for x in inv.move_ids], context=context)
self.write(cr, uid, [inv.id], {'state':'draft'}, context=context)
return True
def action_cancel_inventary(self, cr, uid, ids, context=None):
""" Cancels both stock move and inventory
@return: True
"""
move_obj = self.pool.get('stock.move')
account_move_obj = self.pool.get('account.move')
for inv in self.browse(cr, uid, ids, context=context):
self.pool.get('stock.move').action_cancel(cr, uid, [x.id for x in inv.move_ids], context)
self.write(cr, uid, [inv.id], {'state':'cancel'})
move_obj.action_cancel(cr, uid, [x.id for x in inv.move_ids], context=context)
for move in inv.move_ids:
account_move_ids = account_move_obj.search(cr, uid, [('name', '=', move.name)])
if account_move_ids:
account_move_data_l = account_move_obj.read(cr, uid, account_move_ids, ['state'], context=context)
for account_move in account_move_data_l:
if account_move['state'] == 'posted':
raise osv.except_osv(_('UserError'),
_('You can not cancel inventory which has any account move with posted state.'))
account_move_obj.unlink(cr, uid, [account_move['id']], context=context)
self.write(cr, uid, [inv.id], {'state': 'cancel'}, context=context)
return True
stock_inventory()

View File

@ -170,11 +170,11 @@
<group col="2" colspan="2">
<field name="state"/>
</group>
<group col="2" colspan="2">
<button name="action_cancel_inventary" states="draft" string="Cancel Inventory" type="object" icon="gtk-cancel"/>
<group col="3" colspan="2">
<button name="action_cancel_inventary" states="draft,confirm,done" string="Cancel Inventory" type="object" icon="gtk-cancel"/>
<button name="action_confirm" states="draft" string="Confirm Inventory" type="object" icon="gtk-apply"/>
<button name="action_done" states="confirm" string="Validate Inventory" type="object" icon="gtk-jump-to"/>
<button name="action_cancel" states="cancel" string="Set to Draft" type="object" icon="gtk-convert"/>
<button name="action_cancel_draft" states="cancel" string="Set to Draft" type="object" icon="gtk-convert"/>
</group>
</form>
</field>
@ -773,7 +773,7 @@
<button name="action_assign" states="confirmed" string="Check Availability" type="object" icon="gtk-find"/>
<button name="force_assign" states="confirmed" string="Force Availability" type="object" icon="gtk-jump-to"/>
<button name="action_process" states="assigned" string="Process" groups="stock.group_stock_user" type="object" icon="gtk-go-forward"/>
<button states="done" name="%(action_stock_invoice_onshipping)d" string="Create Invoice" type="action" icon="terp-gtk-go-back-rtl" />
<button states="done" name="%(action_stock_invoice_onshipping)d" string="Create Invoice" attrs="{'invisible': ['|',('invoice_state','=','invoiced'),('invoice_state','=','none')]}" type="action" icon="terp-gtk-go-back-rtl" />
</group>
</page>
<page string="Additional info" groups="base.group_extended,base.group_multi_company">
@ -967,7 +967,7 @@
<button name="force_assign" states="confirmed" string="Force Availability" type="object" icon="gtk-jump-to"/>
<button name="action_process" states="assigned" string="Process" type="object" icon="gtk-go-forward"/>
<button name="%(act_stock_return_picking)d" string="Return Products" states="done" type="action" icon="gtk-execute"/>
<button name="%(action_stock_invoice_onshipping)d" string="Create Invoice" states="done" type="action" icon="terp-gtk-go-back-rtl"/>
<button name="%(action_stock_invoice_onshipping)d" string="Create Invoice" states="done" attrs="{'invisible': ['|',('invoice_state','=','invoiced'),('invoice_state','=','none')]}" type="action" icon="terp-gtk-go-back-rtl"/>
</group>
</page>
<page string="Additional info" groups="base.group_extended,base.group_multi_company">
@ -1189,7 +1189,7 @@
<group colspan="1" states="done">
<button name="%(act_stock_return_picking)d" string="Return Products" states="done" type="action" icon="gtk-execute"/>
</group>
<button name="%(action_stock_invoice_onshipping)d" string="Create Invoice" type="action" icon="terp-gtk-go-back-rtl"/>
<button name="%(action_stock_invoice_onshipping)d" string="Create Invoice" attrs="{'invisible': ['|',('invoice_state','=','invoiced'),('invoice_state','=','none')]}" type="action" icon="terp-gtk-go-back-rtl" />
</group>
</page>
<page string="Additional Info" groups="base.group_extended,base.group_multi_company">

View File

@ -32,6 +32,19 @@ class stock_change_product_qty(osv.osv_memory):
'location_id': fields.many2one('stock.location', 'Location', required=True, domain="[('usage', '=', 'internal')]"),
}
def fields_view_get(self, cr, uid, view_id=None, view_type='form', context=None, toolbar=False, submenu=False):
result = super(stock_change_product_qty, self).fields_view_get(cr, uid, view_id, view_type, context, toolbar, submenu)
product_id = context and context.get('active_id', False) or False
if (context.get('active_model') == 'product.product') and product_id:
prod_obj = self.pool.get('product.product').browse(cr, uid, product_id, context=context)
fields = result.get('fields', {})
if fields and (prod_obj.track_production == True) and (fields.get('prodlot_id')):
result['fields']['prodlot_id']['required'] = True
else:
result['fields']['prodlot_id']['required'] = False
return result
def default_get(self, cr, uid, fields, context):
""" To get default values for the object.
@param self: The object pointer.

View File

@ -85,34 +85,18 @@ class stock_invoice_onshipping(osv.osv_memory):
raise osv.except_osv(_('Warning !'), _('None of these picking lists require invoicing.'))
return res
def create_invoice(self, cr, uid, ids, context=None):
def open_invoice(self, cr, uid, ids, context=None):
if context is None:
context = {}
picking_pool = self.pool.get('stock.picking')
data_pool = self.pool.get('ir.model.data')
onshipdata_obj = self.read(cr, uid, ids[0], ['journal_id', 'group', 'invoice_date'])
if context.get('new_picking', False):
onshipdata_obj['id'] = onshipdata_obj.new_picking
onshipdata_obj[ids] = onshipdata_obj.new_picking
context['date_inv'] = onshipdata_obj['invoice_date']
invoice_ids = []
active_ids = context.get('active_ids', [])
active_picking = picking_pool.browse(cr, uid, context.get('active_id',False), context=context)
inv_type = picking_pool._get_invoice_type(active_picking)
res = picking_pool.action_invoice_create(cr, uid, active_ids,
journal_id = onshipdata_obj['journal_id'],
group = onshipdata_obj['group'],
type = None,
context=context)
data_pool = self.pool.get('ir.model.data')
res = self.create_invoice(cr, uid, ids, context=context)
invoice_ids += res.values()
if not invoice_ids:
raise osv.except_osv(_('Error'), _('No Invoices were created'))
inv_type = context.get('inv_type', False)
action_model = False
action = {}
if not invoice_ids:
raise osv.except_osv(_('Error'), _('No Invoices were created'))
if inv_type == "out_invoice":
action_model,action_id = data_pool.get_object_reference(cr, uid, 'account', "action_invoice_tree1")
elif inv_type == "in_invoice":
@ -127,6 +111,26 @@ class stock_invoice_onshipping(osv.osv_memory):
action['domain'] = "[('id','in', ["+','.join(map(str,invoice_ids))+"])]"
return action
def create_invoice(self, cr, uid, ids, context=None):
if context is None:
context = {}
picking_pool = self.pool.get('stock.picking')
onshipdata_obj = self.read(cr, uid, ids, ['journal_id', 'group', 'invoice_date'])
if context.get('new_picking', False):
onshipdata_obj['id'] = onshipdata_obj.new_picking
onshipdata_obj[ids] = onshipdata_obj.new_picking
context['date_inv'] = onshipdata_obj[0]['invoice_date']
active_ids = context.get('active_ids', [])
active_picking = picking_pool.browse(cr, uid, context.get('active_id',False), context=context)
inv_type = picking_pool._get_invoice_type(active_picking)
context['inv_type'] = inv_type
res = picking_pool.action_invoice_create(cr, uid, active_ids,
journal_id = onshipdata_obj[0]['journal_id'],
group = onshipdata_obj[0]['group'],
type = None,
context=context)
return res
stock_invoice_onshipping()
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

View File

@ -15,7 +15,7 @@
<field name="invoice_date" />
<separator string="" colspan="4" />
<button special="cancel" string="_Cancel" icon='gtk-cancel'/>
<button name="create_invoice" string="Create" type="object" icon="terp-gtk-go-back-rtl"/>
<button name="open_invoice" string="Create" type="object" icon="terp-gtk-go-back-rtl"/>
</form>
</field>
</record>

View File

@ -33,51 +33,71 @@ class stock_partial_picking(osv.osv_memory):
'product_moves_in' : fields.one2many('stock.move.memory.in', 'wizard_id', 'Moves'),
}
def __is_in(self,cr, uid, pick_ids):
def get_picking_type(self, cr, uid, picking, context=None):
picking_type = picking.type
for move in picking.move_lines:
if picking.type == 'in' and move.product_id.cost_method == 'average':
picking_type = 'in'
break
else:
picking_type = 'out'
return picking_type
def default_get(self, cr, uid, fields, context=None):
""" To get default values for the object.
@param self: The object pointer.
@param cr: A database cursor
@param uid: ID of the user currently logged in
@param fields: List of fields for which we want default values
@param context: A standard dictionary
@return: A dictionary which of fields with values.
"""
@return: True if one of the moves has as picking type 'in'
"""
if not pick_ids:
return False
if context is None:
context = {}
pick_obj = self.pool.get('stock.picking')
res = super(stock_partial_picking, self).default_get(cr, uid, fields, context=context)
picking_ids = context.get('active_ids', [])
if not picking_ids:
return res
result = []
for pick in pick_obj.browse(cr, uid, picking_ids, context=context):
pick_type = self.get_picking_type(cr, uid, pick, context=context)
for m in pick.move_lines:
if m.state in ('done', 'cancel'):
continue
result.append(self.__create_partial_picking_memory(m, pick_type))
if 'product_moves_in' in fields:
res.update({'product_moves_in': result})
if 'product_moves_out' in fields:
res.update({'product_moves_out': result})
if 'date' in fields:
res.update({'date': time.strftime('%Y-%m-%d %H:%M:%S')})
return res
def fields_view_get(self, cr, uid, view_id=None, view_type='form', context=None, toolbar=False, submenu=False):
result = super(stock_partial_picking, self).fields_view_get(cr, uid, view_id, view_type, context, toolbar, submenu)
pick_obj = self.pool.get('stock.picking')
pick_ids = pick_obj.search(cr, uid, [('id','in',pick_ids)])
for pick in pick_obj.browse(cr, uid, pick_ids):
for move in pick.move_lines:
if pick.type == 'in' and move.product_id.cost_method == 'average':
return True
return False
def __get_picking_type(self, cr, uid, pick_ids):
if self.__is_in(cr, uid, pick_ids):
return "product_moves_in"
else:
return "product_moves_out"
def view_init(self, cr, uid, fields_list, context=None):
res = super(stock_partial_picking, self).view_init(cr, uid, fields_list, context=context)
return res
def fields_view_get(self, cr, uid, view_id=None, view_type='form', context=None, toolbar=False,submenu=False):
result = super(stock_partial_picking, self).fields_view_get(cr, uid, view_id, view_type, context, toolbar,submenu)
picking_ids = context.get('active_ids', False)
picking_type = self.__get_picking_type(cr, uid, picking_ids)
for pick in pick_obj.browse(cr, uid, picking_ids, context=context):
picking_type = self.get_picking_type(cr, uid, pick, context=context)
_moves_arch_lst = """<form string="%s">
<field name="date" invisible="1"/>
<separator colspan="4" string="%s"/>
<field name="%s" colspan="4" nolabel="1" mode="tree,form" width="550" height="200" ></field>
""" % (_('Process Document'), _('Products'), picking_type)
""" % (_('Process Document'), _('Products'), "product_moves_" + picking_type)
_moves_fields = result['fields']
# add field related to picking type only
_moves_fields.update({
'product_moves_in' : {'relation': 'stock.move.memory.in', 'type' : 'one2many', 'string' : 'Product Moves'},
'product_moves_out' : {'relation': 'stock.move.memory.out', 'type' : 'one2many', 'string' : 'Product Moves'}
'product_moves_' + picking_type: {'relation': 'stock.move.memory.'+picking_type, 'type' : 'one2many', 'string' : 'Product Moves'},
})
_moves_arch_lst += """
<separator string="" colspan="4" />
<label string="" colspan="2"/>
@ -92,44 +112,22 @@ class stock_partial_picking(osv.osv_memory):
result['fields'] = _moves_fields
return result
def __create_partial_picking_memory(self, picking, is_in):
def __create_partial_picking_memory(self, picking, pick_type):
move_memory = {
'product_id' : picking.product_id.id,
'quantity' : picking.product_qty,
'product_uom' : picking.product_uom.id,
'prodlot_id' : picking.prodlot_id.id,
'move_id' : picking.id,
'product_id' : picking.product_id.id,
'quantity' : picking.product_qty,
'product_uom' : picking.product_uom.id,
'prodlot_id' : picking.prodlot_id.id,
'move_id' : picking.id,
}
if is_in:
if pick_type == 'in':
move_memory.update({
'cost' : picking.product_id.standard_price,
'currency' : picking.product_id.company_id and picking.product_id.company_id.currency_id and picking.product_id.company_id.currency_id.id or False,
'cost' : picking.product_id.standard_price,
'currency' : picking.product_id.company_id.currency_id.id,
})
return move_memory
def __get_active_stock_pickings(self, cr, uid, context=None):
pick_obj = self.pool.get('stock.picking')
if not context:
context = {}
res = []
for pick in pick_obj.browse(cr, uid, context.get('active_ids', []), context):
need_product_cost = (pick.type == 'in')
for m in pick.move_lines:
if m.state in ('done', 'cancel'):
continue
res.append(self.__create_partial_picking_memory(m, need_product_cost))
return res
_defaults = {
'product_moves_in' : __get_active_stock_pickings,
'product_moves_out' : __get_active_stock_pickings,
'date' : lambda *a : time.strftime('%Y-%m-%d %H:%M:%S'),
}
def do_partial(self, cr, uid, ids, context=None):
""" Makes partial moves and pickings done.
@param self: The object pointer.
@ -140,6 +138,9 @@ class stock_partial_picking(osv.osv_memory):
@return: A dictionary which of fields with values.
"""
pick_obj = self.pool.get('stock.picking')
move_obj = self.pool.get('stock.move')
location_obj = self.pool.get('stock.location')
picking_ids = context.get('active_ids', False)
partial = self.browse(cr, uid, ids[0], context=context)
partial_datas = {
@ -147,40 +148,24 @@ class stock_partial_picking(osv.osv_memory):
}
for pick in pick_obj.browse(cr, uid, picking_ids, context=context):
need_product_cost = (pick.type == 'in')
moves_list = need_product_cost and partial.product_moves_in or partial.product_moves_out
p_moves = {}
for product_move in moves_list:
p_moves[product_move.move_id.id] = product_move
for move in pick.move_lines:
if move.state in ('done', 'cancel'):
continue
if not p_moves.get(move.id):
continue
partial_datas['move%s' % (move.id)] = {
'product_id' : p_moves[move.id].id,
'product_qty' : p_moves[move.id].quantity,
'product_uom' :p_moves[move.id].product_uom.id,
'prodlot_id' : p_moves[move.id].prodlot_id.id,
picking_type = self.get_picking_type(cr, uid, pick, context=context)
moves_list = picking_type == 'in' and partial.product_moves_in or partial.product_moves_out
for move in moves_list:
partial_datas['move%s' % (move.move_id.id)] = {
'product_id': move.id,
'product_qty': move.quantity,
'product_uom': move.product_uom.id,
'prodlot_id': move.prodlot_id.id,
}
if (move.picking_id.type == 'in') and (move.product_id.cost_method == 'average'):
partial_datas['move%s' % (move.id)].update({
'product_price' : p_moves[move.id].cost,
'product_currency': p_moves[move.id].currency.id,
if (picking_type == 'in') and (move.product_id.cost_method == 'average'):
partial_datas['move%s' % (move.move_id.id)].update({
'product_price' : move.cost,
'product_currency': move.currency.id,
})
pick_obj.do_partial(cr, uid, picking_ids, partial_datas, context=context)
return {'type': 'ir.actions.act_window_close'}
return {}
stock_partial_picking()
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

View File

@ -53,10 +53,8 @@ class stock_return_picking(osv.osv_memory):
res['invoice_state'] = 'none'
for line in pick.move_lines:
return_id = 'return%s'%(line.id)
return_price = 'return_price%s'%(line.id)
if return_id in fields:
res[return_id] = line.product_qty
res[return_price]=line.price_unit
return res
def view_init(self, cr, uid, fields_list, context=None):
@ -88,11 +86,8 @@ class stock_return_picking(osv.osv_memory):
valid_lines += 1
if 'return%s'%(m.id) not in self._columns:
self._columns['return%s'%(m.id)] = fields.float(string=m.name, required=True)
if 'return_price%s'%(m.id) not in self._columns:
self._columns['return_price%s'%(m.id)] = fields.float(string=m.name, required=True)
if 'invoice_state' not in self._columns:
self._columns['invoice_state'] = fields.selection([('2binvoiced', 'To be refunded/invoiced'), ('none', 'No invoicing')], string='Invoicing', required=True)
if not valid_lines:
raise osv.except_osv(_('Warning !'), _("There are no products to return (only lines in Done state and not fully returned yet can be returned)!"))
return res
@ -126,10 +121,6 @@ class stock_return_picking(osv.osv_memory):
if m.state=='done' and quantity > return_history[m.id]:
arch_lst.append('<field name="return%s"/>\n<newline/>' % (m.id,))
res['fields']['return%s' % m.id]={'string':m.name, 'type':'float', 'required':True}
if m.product_id.cost_method == 'average' and pick.type == 'in':
arch_lst.append('<field name="return_price%s"/>\n<newline/>' % (m.id,))
res['fields']['return_price%s' % m.id]={'string':'Price', 'type':'float', 'required':True}
res.setdefault('returns', []).append(m.id)
arch_lst.append('<field name="invoice_state"/>\n<newline/>')
res['fields']['invoice_state']={'string':_('Invoicing'), 'type':'selection','required':True, 'selection':[('2binvoiced', _('To be refunded/invoiced')), ('none', _('No invoicing'))]}
@ -142,7 +133,7 @@ class stock_return_picking(osv.osv_memory):
return res
def create_returns(self, cr, uid, ids, context=None):
"""
"""
Creates return picking.
@param self: The object pointer.
@param cr: A database cursor
@ -152,13 +143,13 @@ class stock_return_picking(osv.osv_memory):
@return: A dictionary which of fields with values.
"""
if context is None:
context = {}
context = {}
record_id = context and context.get('active_id', False) or False
move_obj = self.pool.get('stock.move')
pick_obj = self.pool.get('stock.picking')
uom_obj = self.pool.get('product.uom')
wf_service = netsvc.LocalService("workflow")
pick = pick_obj.browse(cr, uid, record_id, context=context)
data = self.read(cr, uid, ids[0])
new_picking = None
@ -180,7 +171,6 @@ class stock_return_picking(osv.osv_memory):
new_location=move.location_dest_id.id
if move.state=='done':
new_qty = data['return%s' % move.id]
price_unit = data['return_price%s' % move.id]
returned_qty = move.product_qty
for rec in move.move_history_ids2:
@ -188,6 +178,7 @@ class stock_return_picking(osv.osv_memory):
if returned_qty != new_qty:
set_invoice_state_to_none = False
if new_qty:
returned_lines += 1
new_move=move_obj.copy(cr, uid, move.id, {
@ -196,8 +187,7 @@ class stock_return_picking(osv.osv_memory):
new_qty, move.product_uos.id),
'picking_id':new_picking, 'state':'draft',
'location_id':new_location, 'location_dest_id':move.location_id.id,
'date':date_cur,
'price_unit':price_unit})
'date':date_cur,})
move_obj.write(cr, uid, [move.id], {'move_history_ids2':[(4,new_move)]})
if not returned_lines: