bzr revid: hmo@tinyerp.com-20100831101152-pxx8ef3lpyfq4flz
This commit is contained in:
Harry (OpenERP) 2010-08-31 15:41:52 +05:30
commit 906948cb8d
67 changed files with 1276 additions and 1874 deletions

View File

@ -123,7 +123,7 @@ class email_template(osv.osv):
_columns = {
'name' : fields.char('Name', size=100, required=True),
'object_name':fields.many2one('ir.model', 'Model'),
'object_name':fields.many2one('ir.model', 'Resource'),
'model_int_name':fields.char('Model Internal Name', size=200,),
'from_account':fields.many2one(
'email_template.account',
@ -132,7 +132,7 @@ class email_template(osv.osv):
'def_to':fields.char(
'Recipient (To)',
size=250,
help="The default recipient of email."
help="The Recipient of email. "
"Placeholders can be used here."),
'def_cc':fields.char(
'CC',
@ -151,12 +151,12 @@ class email_template(osv.osv):
" Placeholders can be used here."),
'message_id':fields.char('Message-ID',
size=250,
help="The Message-ID header value, if you need to"
"specify it, for example to automatically recognize the replies later."
" Placeholders can be used here."),
'track_campaign_item':fields.boolean('Track campaign items',
help="Enable this if you want the outgoing e-mails to include a tracking"
" marker that makes it possible to identify the replies an link them back to the campaign item"),
help="Specify the Message-ID SMTP header to use in outgoing emails. Please note that this overrides the Resource tracking option! Placeholders can be used here."),
'track_campaign_item':fields.boolean('Resource Tracking',
help="Enable this is you wish to include a special \
tracking marker in outgoing emails so you can identify replies and link \
them back to the corresponding resource record. \
This is useful for CRM leads for example"),
'lang':fields.char(
'Language',
size=250,
@ -164,9 +164,9 @@ class email_template(osv.osv):
" Placeholders can be used here. "
"eg. ${object.partner_id.lang}"),
'def_subject':fields.char(
'Default Subject',
'Subject',
size=200,
help="The default subject of email."
help="The subject of email."
" Placeholders can be used here.",
translate=True),
'def_body_text':fields.text(
@ -201,10 +201,12 @@ class email_template(osv.osv):
'ref_ir_act_window':fields.many2one(
'ir.actions.act_window',
'Window Action',
help="Action that will open this email template on Resource records",
readonly=True),
'ref_ir_value':fields.many2one(
'ir.values',
'Wizard Button',
help="Button in the side bar of the form view of this Resource that will invoke the Window Action",
readonly=True),
'allowed_groups':fields.many2many(
'res.groups',
@ -636,9 +638,13 @@ class email_template(osv.osv):
'mail_type':'multipart/alternative',
}
if template['message_id']:
# use provided message_id with placeholders
mailbox_values.update({'message_id': get_value(cursor, user, record_id, template['message_id'], template, context)})
if template['track_campaign_item']:
# get appropriate message-id
mailbox_values.update(message_id=tools.misc.generate_tracking_message_id(record_id))
mailbox_values.update({'message_id': tools.misc.generate_tracking_message_id(record_id)})
if not mailbox_values['account_id']:
raise Exception("Unable to send the mail. No account linked to the template.")

View File

@ -80,7 +80,12 @@ class email_template_account(osv.osv):
'name': fields.char('Description',
size=64, required=True,
readonly=True, select=True,
help="The description is used as the Sender name along with the provided From Email, \
unless it is already specified in the From Email, e.g: John Doe <john@doe.com>",
states={'draft':[('readonly', False)]}),
'auto_delete': fields.boolean('Auto Delete', size=64, readonly=True,
help="Permanently delete emails after sending",
states={'draft':[('readonly', False)]}),
'user':fields.many2one('res.users',
'Related User', required=True,
readonly=True, states={'draft':[('readonly', False)]}),
@ -133,7 +138,7 @@ class email_template_account(osv.osv):
('suspended', 'Suspended'),
('approved', 'Approved')
],
'Status', required=True, readonly=True),
'State', required=True, readonly=True),
}
_defaults = {
@ -189,25 +194,7 @@ class email_template_account(osv.osv):
'Error: You are not allowed to have more than 1 account.',
[])
]
def on_change_emailid(self, cursor, user, ids, name=None, email_id=None, context=None):
"""
Called when the email ID field changes.
UI enhancement
Writes the same email value to the smtpusername
and incoming username
"""
#TODO: Check and remove the write. Is it needed?
self.write(cursor, user, ids, {'state':'draft'}, context=context)
return {
'value': {
'state': 'draft',
'smtpuname':email_id,
'isuser':email_id
}
}
def get_outgoing_server(self, cursor, user, ids, context=None):
"""
Returns the Out Going Connection (SMTP) object

View File

@ -18,16 +18,17 @@
<notebook colspan="4">
<page string="Outgoing">
<separator string="Server Information" colspan="4" />
<group colspan="4">
<field name="smtpserver" select="1" colspan="2" />
<field name="smtpport" select="2" colspan="2" />
<field name="smtpssl" select="2" colspan="2" />
<field name="smtptls" select="2" colspan="2" />
<group colspan="4" col="4">
<field name="smtpserver" select="1"/>
<field name="smtpport" select="2" />
<field name="smtpssl" select="2" />
<field name="smtptls" select="2" />
<field name="auto_delete" />
</group>
<button name="check_outgoing_connection" type="object" string="Test Outgoing Connection" />
<separator string="User Information" colspan="4" />
<group col="2" colspan="2">
<field name="email_id" select="1" on_change="on_change_emailid(name,email_id)" colspan="2" />
<field name="email_id" select="1" colspan="2" />
<field name="smtppass" password="True" colspan="2" />
<field name="company" select="2" colspan="2" />
</group>
@ -72,15 +73,16 @@
<field name="type">search</field>
<field name="arch" type="xml">
<search string="Accounts">
<filter icon="terp-personal" string="My Accounts" name="my" domain="[('user','=',uid)]"/>
<filter icon="terp-personal+" string="Personal Accounts" domain="[('company','=','no')]"/>
<filter icon="terp-go-home" string="Company Accounts" domain="[('company','=','yes')]"/>
<separator orientation="vertical"/>
<filter icon="terp-document-new" string="Draft" name="draft" domain="[('state','=','draft')]"/>
<filter icon="terp-camera_test" string="Approved" domain="[('state','=','approved')]"/>
<filter icon="terp-emblem-important" string="Suspended" domain="[('state','=','suspended')]"/>
<separator orientation="vertical"/>
<filter icon="terp-go-home" string="Company Accounts" domain="[('company','=','yes')]"/>
<separator orientation="vertical"/>
<field name="user" select="1">
<filter icon="terp-personal" help="My Accounts" name="my" domain="[('user','=',uid)]"/>
</field>
<field name="name" select="1"/>
<field name="user" select="1"/>
<field name="email_id" select="1"/>
</search>
</field>
@ -97,11 +99,25 @@
</record>
<menuitem name="Configuration" parent="base.marketing_menu"
id="base.menu_marketing_config_root" sequence="20" groups="base.group_system"/>
<menuitem name="Emails" id="menu_email_template_configuration" parent="base.menu_marketing_config_root" />
id="base.menu_marketing_config_root" sequence="20" groups="base.group_system"/>
<menuitem name="Email Template" id="menu_email_template_configuration" parent="base.menu_marketing_config_root" />
<menuitem name="Email Accounts" id="menu_email_template_account_all" parent="menu_email_template_configuration" action="action_email_template_account_tree_all"/>
<!-- Email Template account menu in Tools -->
<menuitem name="Tools" id="base.menu_tools" icon="STOCK_PREFERENCES" sequence="28"/>
<menuitem name="Configuration" parent="base.menu_tools"
id="base.menu_lunch_survey_root" sequence="20" />
<menuitem name="Email Template" id="menu_email_template_config_tools"
parent="base.menu_lunch_survey_root" />
<menuitem name="Email Accounts" id="menu_email_account_all_tools"
parent="menu_email_template_config_tools" action="action_email_template_account_tree_all" />
</data>
</openerp>

View File

@ -63,6 +63,7 @@ class email_template_mailbox(osv.osv):
def send_this_mail(self, cr, uid, ids=None, context=None):
result = True
attachment_pool = self.pool.get('ir.attachment')
for id in (ids or []):
try:
account_obj = self.pool.get('email_template.account')
@ -70,7 +71,7 @@ class email_template_mailbox(osv.osv):
payload = {}
if values['attachments_ids']:
for attid in values['attachments_ids']:
attachment = self.pool.get('ir.attachment').browse(cr, uid, attid, context)#,['datas_fname','datas'])
attachment = attachment_pool.browse(cr, uid, attid, context)#,['datas_fname','datas'])
payload[attachment.datas_fname] = attachment.datas
result = account_obj.send_mail(cr, uid,
[values['account_id'][0]],
@ -84,8 +85,15 @@ class email_template_mailbox(osv.osv):
message_id=values['message_id'],
context=context)
if result == True:
self.write(cr, uid, id, {'folder':'sent', 'state':'na', 'date_mail':time.strftime("%Y-%m-%d %H:%M:%S")}, context)
self.historise(cr, uid, [id], "Email sent successfully", context)
account = account_obj.browse(cr, uid, values['account_id'][0], context=context)
if account.auto_delete:
self.write(cr, uid, id, {'folder': 'trash'}, context=context)
self.unlink(cr, uid, [id], context=context)
# Remove attachments for this mail
attachment_pool.unlink(cr, uid, values['attachments_ids'], context=context)
else:
self.write(cr, uid, id, {'folder':'sent', 'state':'na', 'date_mail':time.strftime("%Y-%m-%d %H:%M:%S")}, context)
self.historise(cr, uid, [id], "Email sent successfully", context)
else:
error = result['error_msg']
self.historise(cr, uid, [id], error, context)
@ -100,7 +108,7 @@ class email_template_mailbox(osv.osv):
def historise(self, cr, uid, ids, message='', context=None):
for id in ids:
history = self.read(cr, uid, id, ['history'], context).get('history', '')
self.write(cr, uid, id, {'history':history or '' + "\n" + time.strftime("%Y-%m-%d %H:%M:%S") + ": " + tools.ustr(message)}, context)
self.write(cr, uid, id, {'history': (history or '' )+ "\n" + time.strftime("%Y-%m-%d %H:%M:%S") + ": " + tools.ustr(message)}, context)
_columns = {
'email_from':fields.char(
@ -171,8 +179,7 @@ class email_template_mailbox(osv.osv):
('na', 'Not Applicable'),
('sending', 'Sending'),
], 'Status', required=True),
'date_mail':fields.datetime(
'Rec/Sent Date'),
'date_mail':fields.datetime('Rec/Sent Date', help="Date on which Email Sent or Received"),
'history':fields.text(
'History',
readonly=True,
@ -184,6 +191,24 @@ class email_template_mailbox(osv.osv):
'folder': lambda * a: 'outbox',
}
def unlink(self, cr, uid, ids, context=None):
"""
It just changes the folder of the item to "Trash", if it is no in Trash folder yet,
or completely deletes it if it is already in Trash.
"""
if not context:
context = {}
to_update = []
to_remove = []
for mail in self.browse(cr, uid, ids, context=context):
if mail.folder == 'trash':
to_remove.append(mail.id)
else:
to_update.append(mail.id)
# Changes the folder to trash
self.write(cr, uid, to_update, {'folder': 'trash'}, context=context)
return super(email_template_mailbox, self).unlink(cr, uid, to_remove, context=context)
email_template_mailbox()
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

View File

@ -7,7 +7,7 @@
<field name="model">email_template.mailbox</field>
<field name="type">form</field>
<field name="arch" type="xml">
<form string="Outbox">
<form string="Emails">
<group col="4" colspan="4" name="headers">
<field name="email_from" select="1"/>
<field name="email_to" required="1" select="1" />
@ -28,32 +28,27 @@
<field name="body_html" nolabel="1" colspan="4" />
</page>
</notebook>
<separator colspan="4" string="" />
<group col="4" colspan="4">
<field name="state" readonly="1" string="State"/>
<button name="send_this_mail" type="object" string="Send Mail" icon="terp-mail-message-new"/>
</group>
</page>
<page string="Attachments">
<group col="4">
<separator colspan="4" string="Attachments" />
<field name="attachments_ids" colspan="4" nolabel="1" />
</group>
<separator colspan="4" string="Attachments" />
<field name="attachments_ids" colspan="4" nolabel="1" />
</page>
<page string="Advanced">
<group col="4">
<field name="account_id" colspan="2" />
<field name="server_ref" colspan="2" />
<field name="mail_type" colspan="2" />
<field name="folder" colspan="2" select="2"/>
<field name="message_id" select="2"/>
<separator string="History" colspan="4" />
<field name="history" nolabel="1" colspan="4"/>
</group>
<field name="account_id" colspan="2" />
<field name="server_ref" colspan="2" />
<field name="mail_type" colspan="2" />
<field name="folder" colspan="2" select="2"/>
<field name="message_id" select="2"/>
<separator string="History" colspan="4" />
<field name="history" nolabel="1" colspan="4"/>
</page>
</notebook>
<separator colspan="4" string="" />
<group col="4" colspan="4">
<field name="state" readonly="1" />
<button name="complete_mail" type="object" string="Download Full Mail" states="read,unread" />
<button name="send_this_mail" type="object" string="Send Mail" />
</group>
</form>
</field>
</record>
@ -64,12 +59,14 @@
<field name="model">email_template.mailbox</field>
<field name="type">tree</field>
<field name="arch" type="xml">
<tree string="Drafts">
<tree string="Emails" colors="blue:folder=='drafts';grey:folder=='trash'">
<field name="subject" select="1" />
<field name="user" />
<field name="email_from" select="1" />
<field name="subject" select="1" />
<field name="attachments_ids" select="2" />
<field name="email_to"/>
<field name="date_mail" select="2" />
<field name="attachments_ids" select="2" />
<field name="folder" invisible="1"/>
</tree>
</field>
</record>
@ -79,37 +76,54 @@
<field name="model">email_template.mailbox</field>
<field name="type">search</field>
<field name="arch" type="xml">
<search string="Mailboxes">
<filter icon="terp-mail-message-new" string="Drafts" name="draft" domain="[('folder','=','drafts')]"/>
<search string="Emails">
<filter icon="terp-document-new" string="Drafts" name="draft" domain="[('folder','=','drafts')]"/>
<filter icon="terp-mail-" string="Outbox" name="outbox" domain="[('folder','=','outbox')]"/>
<separator orientation="vertical"/>
<filter icon="terp-gtk-jump-to-ltr" string="Sent" domain="[('folder','=','sent')]"/>
<filter icon="terp-camera_test" string="Sent" domain="[('folder','=','sent')]"/>
<filter icon="terp-mail_delete" string="Trash" domain="[('folder','=','trash')]"/>
<separator orientation="vertical"/>
<filter icon="terp-gtk-stop" string="Not Applicable" domain="[('state','=','na')]"/>
<filter icon="terp-gtk-jump-to-ltr" string="Sending" domain="[('state','=','sending')]"/>
<filter icon="terp-personal+" string="Personal Emails" name="personal" domain="[('account_id.company','=','no')]"/>
<filter icon="terp-go-home" string="Company Emails" name="company" domain="[('account_id.company','=','yes')]"/>
<separator orientation="vertical"/>
<field name="email_from" select="1"/>
<field name="email_to" select="1"/>
<field name="subject" select="1"/>
<field name="subject"/>
<field name="email_from"/>
<field name="user">
<filter icon="terp-personal"
string="My Emails" name="myemails"
domain="[('account_id.user','=', uid)]" />
</field>
<newline/>
<field name="email_to"/>
<field name="date_mail"/>
</search>
</field>
</record>
<record model="ir.actions.act_window" id="action_email_template_mailbox">
<field name="name">Mailbox</field>
<field name="name">Emails</field>
<field name="res_model">email_template.mailbox</field>
<field name="view_type">form</field>
<field name="view_mode">form,tree</field>
<field name="view_mode">tree,form</field>
<field name="view_id" ref="view_email_template_mailbox_tree" />
<field name="context">{'group_by': [], 'search_default_draft': 1, 'search_default_outbox': 1}</field>
<field name="context">{'group_by': [], 'search_default_outbox': 1}</field>
<field name="search_view_id" ref="view_email_template_mailbox_search"/>
</record>
<!--======================================== MENUS ========================================-->
<menuitem name="MailBox" id="menu_email_template_mailbox_all_main2" parent="menu_email_template" />
<menuitem name="Personal Mails" id="menu_email_template_personal_mails" parent="menu_email_template_mailbox_all_main2" action="action_email_template_mailbox"/>
<menuitem name="Company Mails" id="menu_email_template_company_mails" parent="menu_email_template_mailbox_all_main2" action="action_email_template_mailbox"/>
<menuitem name="Emails"
id="menu_email_template_personal_mails"
parent="menu_email_template"
action="action_email_template_mailbox" />
<!-- Mailbox menu in Tools -->
<menuitem name="Email Template" id="menu_email_template_tools"
parent="base.menu_tools" />
<menuitem name="Emails"
id="menu_email_template_mails_tools"
parent="menu_email_template_tools"
action="action_email_template_mailbox" />
</data>
</openerp>

View File

@ -1,12 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<openerp>
<data noupdate="1">
<record forcecreate="True" id="ir_cron_mail_scheduler_action" model="ir.cron">
<record forcecreate="True" id="ir_cron_mail_scheduler_action" model="ir.cron">
<field name="name">Email Template scheduler</field>
<field name="user_id" ref="base.user_root"/>
<field name="interval_number">1</field>
<field name="interval_type">hours</field>
<field name="numbercall">12</field>
<field name="numbercall">-1</field>
<field eval="False" name="doall"/>
<field eval="'email_template.mailbox'" name="model"/>
<field eval="'run_mail_scheduler'" name="function"/>

View File

@ -1,7 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<openerp>
<data>
<!-- Email Template PReview -->
<!-- Email Template Preview -->
<record model="ir.ui.view" id="email_template_preview_form">
<field name="name">email_template.preview.form</field>
<field name="model">email_template.preview</field>
@ -67,25 +68,26 @@
<field name="reply_to"/>
</group>
<group col="2" colspan="2">
<separator string="Email Data" colspan="2"/>
<field name="def_subject" colspan="4" required="1" />
<field name="use_sign" colspan="4" />
<separator string="Options" colspan="2"/>
<field name="lang" colspan="4" />
<field name="use_sign" colspan="4" />
<field name="track_campaign_item" colspan="4"/>
</group>
<separator colspan="3" string="Standard Body" />
<separator colspan="1" string="Expression Builder" />
<notebook>
<page string="Body (Text)">
<field name="def_body_text" colspan="4" nolabel="1" />
</page>
<page string="Body (Raw HTML)">
<field name="def_body_html" colspan="4" nolabel="1" />
<label string="Note: This is Raw HTML." colspan="4" />
</page>
</notebook>
<group col="4">
<group col="2" colspan="2">
<separator colspan="2" string="Email Content " />
<field name="def_subject" colspan="4" required="1" />
<notebook>
<page string="Body (Text)">
<field name="def_body_text" colspan="4" nolabel="1" />
</page>
<page string="Body (Raw HTML)">
<field name="def_body_html" colspan="4" nolabel="1" />
<label string="Note: This is Raw HTML." colspan="4" />
</page>
</notebook>
</group>
<group col="4" colspan="2">
<separator colspan="4" string="Expression Builder" />
<field name="template_language"
on_change="onchange_null_value(model_object_field,sub_model_object_field,null_value,template_language,context)" />
<notebook>
@ -112,17 +114,23 @@
</page>
<page string="Advanced">
<group colspan="2" col="2">
<separator string="Actions" colspan="2"/>
<button name="create_action" string="Create Action" type="object" colspan="2" attrs="{'invisible':[('ref_ir_act_window','!=',False), ('ref_ir_value','!=',False)]}"/>
<field name="ref_ir_act_window"/>
<field name="ref_ir_value"/>
<button name="delete_action" string="Delete Action" type="object" colspan="2" attrs="{'invisible':[('ref_ir_act_window','=',False), ('ref_ir_value','=',False)]}"/>
<group colspan="2" col="2">
<separator string="Actions" colspan="2"/>
<button name="create_action" string="Create Action" type="object" colspan="2" attrs="{'invisible':[('ref_ir_act_window','!=',False), ('ref_ir_value','!=',False)]}"/>
<field name="ref_ir_act_window"/>
<field name="ref_ir_value"/>
<button name="delete_action" string="Delete Action" type="object" colspan="2" attrs="{'invisible':[('ref_ir_act_window','=',False), ('ref_ir_value','=',False)]}"/>
</group>
<group colspan="2" col="2">
<separator string="Advanced Options" colspan="2"/>
<field name="message_id"/>
</group>
</group>
<group colspan="2" col="2">
<separator string="Attachments" colspan="2"/>
<notebook>
<page string="Existing files">
<field name="attachment_ids" colspan="4" nolabel="1"/>
<field name="attachment_ids" colspan="4" nolabel="1" height="350"/>
</page>
<page string="Report">
<field name="file_name" colspan="4" />
@ -183,9 +191,12 @@
<field name="search_view_id" ref="view_email_template_search"/>
</record>
<menuitem name="E-MAIL Templates" id="menu_email_template_all"
<menuitem name="Email Templates" id="menu_email_template_all"
parent="menu_email_template_configuration" action="action_email_template_tree_all" />
<!-- Email Template menu in Tools -->
<menuitem name="Email Templates" id="menu_email_template_all_tools"
parent="menu_email_template_config_tools" action="action_email_template_tree_all" />
</data>
</openerp>

View File

@ -335,11 +335,6 @@ msgstr ""
msgid "Send/Receive"
msgstr ""
#. module: email_template
#: model:ir.ui.menu,name:email_template.menu_email_template_mailbox_all_main2
msgid "MailBox"
msgstr ""
#. module: email_template
#: model:ir.actions.act_window,name:email_template.wizard_email_template_preview
msgid "Template Preview"

View File

@ -174,8 +174,8 @@ msgstr "Approve Account"
#. module: email_template
#: model:ir.ui.menu,name:email_template.menu_email_template_all
msgid "E-MAIL Templates"
msgstr "E-MAIL Templates"
msgid "Email Templates"
msgstr "Email Templates"
#. module: email_template
#: field:email_template.preview,rel_model_ref:0
@ -221,8 +221,8 @@ msgstr "Download Full Mail"
#. module: email_template
#: help:email.template,def_to:0
msgid "The default recipient of email.Placeholders can be used here."
msgstr "The default recipient of email.Placeholders can be used here."
msgid "The recipient of email.Placeholders can be used here."
msgstr "The recipient of email.Placeholders can be used here."
#. module: email_template
#: view:email_template.mailbox:0
@ -258,8 +258,8 @@ msgstr "Accounts"
#. module: email_template
#: field:email.template,track_campaign_item:0
msgid "Track campaign items"
msgstr "Track campaign items"
msgid "Resource Tracking"
msgstr "Resource Tracking"
#. module: email_template
#: view:email_template.preview:0
@ -335,11 +335,6 @@ msgstr "Body(Html)"
msgid "Send/Receive"
msgstr "Send/Receive"
#. module: email_template
#: model:ir.ui.menu,name:email_template.menu_email_template_mailbox_all_main2
msgid "MailBox"
msgstr "MailBox"
#. module: email_template
#: model:ir.actions.act_window,name:email_template.wizard_email_template_preview
msgid "Template Preview"
@ -762,8 +757,8 @@ msgstr "Save in Drafts"
#. module: email_template
#: help:email.template,def_subject:0
msgid "The default subject of email. Placeholders can be used here."
msgstr "The default subject of email. Placeholders can be used here."
msgid "The subject of email. Placeholders can be used here."
msgstr "The subject of email. Placeholders can be used here."
#. module: email_template
#: field:email_template.account,smtptls:0
@ -772,8 +767,8 @@ msgstr "TLS"
#. module: email_template
#: view:email_template.send.wizard:0
msgid "Add here all attachments of the current document you want to include in the e-mail."
msgstr "Add here all attachments of the current document you want to include in the e-mail."
msgid "Add here all attachments of the current document you want to include in the Email."
msgstr "Add here all attachments of the current document you want to include in the Email."
#. module: email_template
#: model:ir.model,name:email_template.model_email_template_send_wizard
@ -786,6 +781,8 @@ msgstr "This is the wizard for sending mail"
#: code:addons/email_template/email_template_mailbox.py:0
#: code:addons/email_template/wizard/email_template_send_wizard.py:0
#: model:ir.ui.menu,name:email_template.menu_email_template
#: model:ir.ui.menu,name:email_template.menu_email_template_config_tools
#: model:ir.ui.menu,name:email_template.menu_email_template_configuration
#, python-format
msgid "Email Template"
msgstr "Email Template"
@ -1023,8 +1020,8 @@ msgstr "Password"
#: help:email.template,message_id:0
#: help:email_template.preview,message_id:0
#: help:email_template.send.wizard,message_id:0
msgid "The Message-ID header value, if you need tospecify it, for example to automatically recognize the replies later. Placeholders can be used here."
msgstr "The Message-ID header value, if you need tospecify it, for example to automatically recognize the replies later. Placeholders can be used here."
msgid "Specify the Message-ID SMTP header to use in outgoing emails. Please note that this overrides the Resource tracking option! Placeholders can be used here."
msgstr "Specify the Message-ID SMTP header to use in outgoing emails. Please note that this overrides the Resource tracking option! Placeholders can be used here."
#. module: email_template
#: model:ir.ui.menu,name:email_template.menu_email_template_configuration
@ -1113,11 +1110,6 @@ msgstr "Corporate"
msgid "Enter name of outgoing server, eg:smtp.gmail.com "
msgstr "Enter name of outgoing server, eg:smtp.gmail.com "
#. module: email_template
#: model:ir.ui.menu,name:email_template.menu_email_template_company_mails
msgid "Company Mails"
msgstr "Company Mails"
#. module: email_template
#: view:email.template:0
msgid "Addresses"
@ -1130,8 +1122,8 @@ msgstr "Emails will be sent from this approved account."
#. module: email_template
#: field:email.template,def_subject:0
msgid "Default Subject"
msgstr "Default Subject"
msgid "Subject"
msgstr "Subject"
#. module: email_template
#: help:email.template,def_bcc:0
@ -1182,8 +1174,8 @@ msgstr "Has Attachments"
#. module: email_template
#: help:email.template,track_campaign_item:0
msgid "Enable this if you want the outgoing e-mails to include a tracking marker that makes it possible to identify the replies an link them back to the campaign item"
msgstr "Enable this if you want the outgoing e-mails to include a tracking marker that makes it possible to identify the replies an link them back to the campaign item"
msgid "Enable this is you wish to include a special tracking marker in outgoing emails so you can identify replies and link them back to the corresponding resource record. This is useful for CRM leads for example"
msgstr "Enable this is you wish to include a special tracking marker in outgoing emails so you can identify replies and link them back to the corresponding resource record. This is useful for CRM leads for example"
#. module: email_template
#: code:addons/email_template/email_template.py:0

View File

@ -348,11 +348,6 @@ msgstr ""
msgid "Send/Receive"
msgstr ""
#. module: email_template
#: model:ir.ui.menu,name:email_template.menu_email_template_mailbox_all_main2
msgid "MailBox"
msgstr ""
#. module: email_template
#: model:ir.actions.act_window,name:email_template.wizard_email_template_preview
msgid "Template Preview"
@ -1145,11 +1140,6 @@ msgstr ""
msgid "Enter name of outgoing server, eg:smtp.gmail.com "
msgstr ""
#. module: email_template
#: model:ir.ui.menu,name:email_template.menu_email_template_company_mails
msgid "Company Mails"
msgstr ""
#. module: email_template
#: view:email.template:0
msgid "Addresses"

View File

@ -33,7 +33,7 @@
<field name="body_html" select="2" colspan="4" nolabel="1" />
</page>
<page string="Attachments">
<label string="Add here all attachments of the current document you want to include in the e-mail." colspan="4"/>
<label string="Add here all attachments of the current document you want to include in the Email." colspan="4"/>
<field name="attachment_ids" colspan="4" nolabel="1"/>
</page>
</notebook>

View File

@ -101,7 +101,7 @@
-
!python {model: hr.sign.in.project}: |
uid = ref('res_users_user0')
new_id = self.create(cr, uid, {'emp_id': 'hr_employee_fracline1', 'name': 'Francline', 'server_date': '2010-06-08 19:50:54', 'state': 'absent'})
new_id = self.create(cr, uid, {'emp_id': ref('hr_employee_fracline1'), 'name': 'Francline', 'server_date': '2010-06-08 19:50:54', 'state': 'absent'})
self.sign_in_result(cr, uid, [new_id], context)
-

View File

@ -32,7 +32,7 @@ class marketing_installer(osv.osv_memory):
'marketing_campaign_mailchimp':fields.boolean('Mailchimp Integration',
help="This modules integrate mailchimp.com's service with OpenERP to automate mass mailings."),
'crm_profiling':fields.boolean('Profiling Tools',
help="Helps you to perform segmentation within partners and design questionaires.")
help="Helps you to perform segmentation within partners and design segmentation questionnaires")
}
marketing_installer()

View File

@ -30,14 +30,16 @@
"author" : "OpenERP SA",
"category": 'Generic Modules/Marketing',
"description": """
Allows you to setup leads automation through marketing campaigns. The campaigns
are dynamic and multi-channels. The process:
* Design marketing campaigns that incluces mail templates, reports to print,
miscelleanous actions, etc.
* Define segments that are selections of target people
* Launch your campaign to automate communications.
If you need demo data, you can install the module marketing_campaign_crm_demo.
This module provides leads automation through marketing campaigns (campaigns can in fact be defined on any resource, not just CRM Leads).
The campaigns are dynamic and multi-channels. The process is as follows:
* Design marketing campaigns like workflows, including email templates to send, reports to print and send by email, custom actions, etc.
* Define input segments that will select the items that should enter the campaign (e.g leads from certain countries, etc.)
* Run you campaign in simulation mode to test it real-time or accelerated, and fine-tune it
* You may also start the real campaign in manual mode, where each action requires manual validation
* Finally launch your campaign live, and watch the statistics as the campaign does everything fully automatically.
While the campaign runs you can of course continue to fine-tune the parameters, input segments, workflow, etc.
Note: If you need demo data, you can install the marketing_campaign_crm_demo module, but this will also install the CRM application as it depends on CRM Leads.
""",
'website': 'http://www.openerp.com',
'init_xml': [],

View File

@ -1,914 +0,0 @@
# Translation of OpenERP Server.
# This file contains the translation of the following modules:
# * marketing_campaign
#
msgid ""
msgstr ""
"Project-Id-Version: OpenERP Server 6.0dev\n"
"Report-Msgid-Bugs-To: support@openerp.com\n"
"POT-Creation-Date: 2010-08-20 07:30:00+0000\n"
"PO-Revision-Date: 2010-08-20 07:30:00+0000\n"
"Last-Translator: <>\n"
"Language-Team: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: \n"
"Plural-Forms: \n"
#. module: marketing_campaign
#: code:addons/marketing_campaign/marketing_campaign.py:0
#, python-format
msgid "The current step for this item has no email or report to preview."
msgstr "The current step for this item has no email or report to preview."
#. module: marketing_campaign
#: selection:marketing.campaign.transition,trigger:0
msgid "Time"
msgstr "Time"
#. module: marketing_campaign
#: view:campaign.analysis:0
#: view:marketing.campaign:0
#: view:marketing.campaign.segment:0
#: view:marketing.campaign.workitem:0
msgid "Group By..."
msgstr "Group By..."
#. module: marketing_campaign
#: field:marketing.campaign.transition,trigger:0
msgid "Trigger"
msgstr "Trigger"
#. module: marketing_campaign
#: constraint:ir.actions.act_window:0
msgid "Invalid model name in the action definition."
msgstr "Invalid model name in the action definition."
#. module: marketing_campaign
#: field:campaign.analysis,count:0
msgid "# of Actions"
msgstr "# of Actions"
#. module: marketing_campaign
#: view:marketing.campaign:0
msgid "Campaign Editor"
msgstr "Campaign Editor"
#. module: marketing_campaign
#: view:campaign.analysis:0
msgid "Today"
msgstr "Today"
#. module: marketing_campaign
#: selection:campaign.analysis,month:0
msgid "March"
msgstr "March"
#. module: marketing_campaign
#: field:marketing.campaign.activity,object_id:0
#: field:marketing.campaign.segment,object_id:0
#: field:marketing.campaign.workitem,object_id:0
msgid "Object"
msgstr "Object"
#. module: marketing_campaign
#: view:marketing.campaign:0
#: view:marketing.campaign.segment:0
msgid "Set to Draft"
msgstr "Set to Draft"
#. module: marketing_campaign
#: field:marketing.campaign.activity,to_ids:0
msgid "Next Activities"
msgstr "Next Activities"
#. module: marketing_campaign
#: view:marketing.campaign.segment:0
msgid "Synchronization"
msgstr "Synchronization"
#. module: marketing_campaign
#: view:campaign.analysis:0
msgid "This Year"
msgstr "This Year"
#. module: marketing_campaign
#: help:marketing.campaign,partner_field_id:0
msgid "The generated workitems will be linked to the partner related to the record. If the record is the partner itself left this field empty."
msgstr "The generated workitems will be linked to the partner related to the record. If the record is the partner itself left this field empty."
#. module: marketing_campaign
#: code:addons/marketing_campaign/marketing_campaign.py:0
#, python-format
msgid "No preview"
msgstr "No preview"
#. module: marketing_campaign
#: view:marketing.campaign.activity:0
msgid "Outgoing Transitions"
msgstr "Outgoing Transitions"
#. module: marketing_campaign
#: view:marketing.campaign.workitem:0
msgid "Reset"
msgstr "Reset"
#. module: marketing_campaign
#: help:marketing.campaign.activity,type:0
msgid "Describe type of action to be performed on the Activity.Eg : Send email,Send paper.."
msgstr "Describe type of action to be performed on the Activity.Eg : Send email,Send paper.."
#. module: marketing_campaign
#: selection:marketing.campaign.transition,interval_type:0
msgid "Year(s)"
msgstr "Year(s)"
#. module: marketing_campaign
#: help:marketing.campaign.activity,report_directory_id:0
msgid "This folder is used to store the generated reports"
msgstr "This folder is used to store the generated reports"
#. module: marketing_campaign
#: view:marketing.campaign:0
#: selection:marketing.campaign,state:0
#: selection:marketing.campaign.segment,state:0
#: selection:marketing.campaign.workitem,state:0
msgid "Cancelled"
msgstr "Cancelled"
#. module: marketing_campaign
#: selection:marketing.campaign.transition,trigger:0
msgid "Automatic"
msgstr "Automatic"
#. module: marketing_campaign
#: view:marketing.campaign.activity:0
msgid "Activity Definition"
msgstr "Activity Definition"
#. module: marketing_campaign
#: field:marketing.campaign.activity,keep_if_condition_not_met:0
msgid "Keep as cancelled when condition not met"
msgstr "Keep as cancelled when condition not met"
#. module: marketing_campaign
#: help:marketing.campaign,mode:0
msgid "Test - It creates and process all the activities directly (without waiting for the delay on transitions) but does not send emails or produce reports.\n"
"Test in Realtime - It creates and processes all the activities directly but does not send emails or produce reports.\n"
"With Manual Confirmation - the campaigns runs normally, but the user has to validate all workitem manually.\n"
"Normal - the campaign runs normally and automatically sends all emails and reports (be very careful with this mode, you're live!)"
msgstr "Test - It creates and process all the activities directly (without waiting for the delay on transitions) but does not send emails or produce reports.\n"
"Test in Realtime - It creates and processes all the activities directly but does not send emails or produce reports.\n"
"With Manual Confirmation - the campaigns runs normally, but the user has to validate all workitem manually.\n"
"Normal - the campaign runs normally and automatically sends all emails and reports (be very careful with this mode, you're live!)"
#. module: marketing_campaign
#: view:campaign.analysis:0
#: field:campaign.analysis,campaign_id:0
#: view:marketing.campaign:0
#: field:marketing.campaign.activity,campaign_id:0
#: view:marketing.campaign.segment:0
#: field:marketing.campaign.segment,campaign_id:0
#: field:marketing.campaign.workitem,campaign_id:0
msgid "Campaign"
msgstr "Campaign"
#. module: marketing_campaign
#: field:marketing.campaign.activity,start:0
msgid "Start"
msgstr "Start"
#. module: marketing_campaign
#: view:campaign.analysis:0
#: field:campaign.analysis,segment_id:0
#: view:marketing.campaign.workitem:0
#: field:marketing.campaign.workitem,segment_id:0
msgid "Segment"
msgstr "Segment"
#. module: marketing_campaign
#: field:marketing.campaign.segment,sync_mode:0
msgid "Workitem creation mode"
msgstr "Workitem creation mode"
#. module: marketing_campaign
#: selection:marketing.campaign.transition,interval_type:0
msgid "Month(s)"
msgstr "Month(s)"
#. module: marketing_campaign
#: code:addons/marketing_campaign/marketing_campaign.py:0
#, python-format
msgid "The campaign hasn't any starting activity nor any activity with a signal and no previous activity."
msgstr "The campaign hasn't any starting activity nor any activity with a signal and no previous activity."
#. module: marketing_campaign
#: view:campaign.analysis:0
#: field:campaign.analysis,partner_id:0
#: model:ir.model,name:marketing_campaign.model_res_partner
#: field:marketing.campaign.workitem,partner_id:0
msgid "Partner"
msgstr "Partner"
#. module: marketing_campaign
#: selection:marketing.campaign.segment,sync_mode:0
msgid "If record created after last sync"
msgstr "If record created after last sync"
#. module: marketing_campaign
#: view:marketing.campaign.activity:0
msgid "Transitions"
msgstr "Transitions"
#. module: marketing_campaign
#: view:marketing.campaign.segment:0
msgid "Create After Sync"
msgstr "Create After Sync"
#. module: marketing_campaign
#: view:marketing.campaign.segment:0
msgid "Dates"
msgstr "Dates"
#. module: marketing_campaign
#: help:marketing.campaign.segment,sync_mode:0
msgid "Determines when new workitems should be created for records matching a segment."
msgstr "Determines when new workitems should be created for records matching a segment."
#. module: marketing_campaign
#: view:campaign.analysis:0
#: view:marketing.campaign:0
#: field:marketing.campaign,state:0
#: view:marketing.campaign.segment:0
#: field:marketing.campaign.segment,state:0
#: view:marketing.campaign.workitem:0
#: field:marketing.campaign.workitem,state:0
msgid "State"
msgstr "State"
#. module: marketing_campaign
#: model:ir.module.module,description:marketing_campaign.module_meta_information
msgid "\n"
"Allows you to setup leads automation through marketing campaigns. The campaigns\n"
"are dynamic and multi-channels. The process:\n"
"* Design marketing campaigns that incluces mail templates, reports to print,\n"
" miscelleanous actions, etc.\n"
"* Define segments that are selections of target people\n"
"* Launch your campaign to automate communications.\n"
"\n"
"If you need demo data, you can install the module marketing_campaign_crm_demo.\n"
" "
msgstr "\n"
"Allows you to setup leads automation through marketing campaigns. The campaigns\n"
"are dynamic and multi-channels. The process:\n"
"* Design marketing campaigns that incluces mail templates, reports to print,\n"
" miscelleanous actions, etc.\n"
"* Define segments that are selections of target people\n"
"* Launch your campaign to automate communications.\n"
"\n"
"If you need demo data, you can install the module marketing_campaign_crm_demo.\n"
" "
#. module: marketing_campaign
#: help:marketing.campaign.activity,condition:0
msgid "Python expression to decide whether the activity can be executed, otherwise it will be deleted or cancelled.The expression may use the following [browsable] variables:\n"
" - activity: the campaign activity\n"
" - workitem: the campaign workitem\n"
" - object: the object this campaign item represents\n"
" - transitions: list of campaign transitions outgoing from this activity\n"
"...- re: Python regular expression module"
msgstr "Python expression to decide whether the activity can be executed, otherwise it will be deleted or cancelled.The expression may use the following [browsable] variables:\n"
" - activity: the campaign activity\n"
" - workitem: the campaign workitem\n"
" - object: the object this campaign item represents\n"
" - transitions: list of campaign transitions outgoing from this activity\n"
"...- re: Python regular expression module"
#. module: marketing_campaign
#: view:campaign.analysis:0
msgid "Marketing Reports"
msgstr "Marketing Reports"
#. module: marketing_campaign
#: field:marketing.campaign.activity,type:0
msgid "Type"
msgstr "Type"
#. module: marketing_campaign
#: field:marketing.campaign.workitem,res_name:0
msgid "Resource Name"
msgstr "Resource Name"
#. module: marketing_campaign
#: view:marketing.campaign:0
#: view:marketing.campaign.segment:0
msgid "Run"
msgstr "Run"
#. module: marketing_campaign
#: code:addons/marketing_campaign/marketing_campaign.py:0
#, python-format
msgid "The campaign cannot be started: an email account is missing in the email activity '%s'"
msgstr "The campaign cannot be started: an email account is missing in the email activity '%s'"
#. module: marketing_campaign
#: field:marketing.campaign.activity,from_ids:0
msgid "Previous Activities"
msgstr "Previous Activities"
#. module: marketing_campaign
#: field:marketing.campaign.transition,activity_from_id:0
msgid "Previous Activity"
msgstr "Previous Activity"
#. module: marketing_campaign
#: view:marketing.campaign.workitem:0
msgid "Marketing Campaign Activities"
msgstr "Marketing Campaign Activities"
#. module: marketing_campaign
#: view:marketing.campaign.workitem:0
#: field:marketing.campaign.workitem,error_msg:0
msgid "Error Message"
msgstr "Error Message"
#. module: marketing_campaign
#: model:ir.actions.act_window,name:marketing_campaign.action_campaign_analysis_all
#: model:ir.actions.act_window,name:marketing_campaign.action_marketing_campaign_form
#: model:ir.ui.menu,name:marketing_campaign.menu_action_campaign_analysis_all
#: model:ir.ui.menu,name:marketing_campaign.menu_marketing_campaign
#: model:ir.ui.menu,name:marketing_campaign.menu_marketing_campaign_form
#: view:marketing.campaign:0
msgid "Campaigns"
msgstr "Campaigns"
#. module: marketing_campaign
#: field:marketing.campaign.transition,interval_type:0
msgid "Interval Unit"
msgstr "Interval Unit"
#. module: marketing_campaign
#: field:campaign.analysis,country_id:0
msgid "Country"
msgstr "Country"
#. module: marketing_campaign
#: selection:campaign.analysis,month:0
msgid "July"
msgstr "July"
#. module: marketing_campaign
#: model:ir.ui.menu,name:marketing_campaign.menu_marketing_configuration
msgid "Configuration"
msgstr "Configuration"
#. module: marketing_campaign
#: constraint:ir.cron:0
msgid "Invalid arguments"
msgstr "Invalid arguments"
#. module: marketing_campaign
#: constraint:ir.ui.view:0
msgid "Invalid XML for View Architecture!"
msgstr "Invalid XML for View Architecture!"
#. module: marketing_campaign
#: selection:marketing.campaign.transition,interval_type:0
msgid "Hour(s)"
msgstr "Hour(s)"
#. module: marketing_campaign
#: model:ir.model,name:marketing_campaign.model_marketing_campaign_segment
msgid "Campaign Segment"
msgstr "Campaign Segment"
#. module: marketing_campaign
#: view:marketing.campaign.segment:0
#: view:marketing.campaign.workitem:0
msgid "Cancel"
msgstr "Cancel"
#. module: marketing_campaign
#: help:marketing.campaign.activity,keep_if_condition_not_met:0
msgid "By activating this option, workitems that aren't executed because the condition is not met are marked as cancelled instead of being deleted."
msgstr "By activating this option, workitems that aren't executed because the condition is not met are marked as cancelled instead of being deleted."
#. module: marketing_campaign
#: view:campaign.analysis:0
msgid "Exceptions"
msgstr "Exceptions"
#. module: marketing_campaign
#: field:res.partner,workitem_ids:0
msgid "Workitems"
msgstr "Workitems"
#. module: marketing_campaign
#: field:marketing.campaign,fixed_cost:0
msgid "Fixed Cost"
msgstr "Fixed Cost"
#. module: marketing_campaign
#: field:marketing.campaign.transition,interval_nbr:0
msgid "Interval Value"
msgstr "Interval Value"
#. module: marketing_campaign
#: field:campaign.analysis,revenue:0
#: field:marketing.campaign.activity,revenue:0
msgid "Revenue"
msgstr "Revenue"
#. module: marketing_campaign
#: selection:campaign.analysis,month:0
msgid "September"
msgstr "September"
#. module: marketing_campaign
#: selection:campaign.analysis,month:0
msgid "December"
msgstr "December"
#. module: marketing_campaign
#: view:campaign.analysis:0
#: field:campaign.analysis,month:0
msgid "Month"
msgstr "Month"
#. module: marketing_campaign
#: field:marketing.campaign.transition,activity_to_id:0
msgid "Next Activity"
msgstr "Next Activity"
#. module: marketing_campaign
#: field:marketing.campaign.activity,email_template_id:0
msgid "The e-mail to send when this activity is activated"
msgstr "The e-mail to send when this activity is activated"
#. module: marketing_campaign
#: view:campaign.analysis:0
msgid "This Month"
msgstr "This Month"
#. module: marketing_campaign
#: view:marketing.campaign:0
msgid "Test Mode"
msgstr "Test Mode"
#. module: marketing_campaign
#: model:ir.model,name:marketing_campaign.model_ir_actions_report_xml
msgid "ir.actions.report.xml"
msgstr "ir.actions.report.xml"
#. module: marketing_campaign
#: view:marketing.campaign:0
msgid "Manual Mode"
msgstr "Manual Mode"
#. module: marketing_campaign
#: help:marketing.campaign.activity,server_action_id:0
msgid "The action to perform when this activity is activated"
msgstr "The action to perform when this activity is activated"
#. module: marketing_campaign
#: field:marketing.campaign,partner_field_id:0
msgid "Partner Field"
msgstr "Partner Field"
#. module: marketing_campaign
#: model:ir.model,name:marketing_campaign.model_campaign_analysis
msgid "Campaign Analysis"
msgstr "Campaign Analysis"
#. module: marketing_campaign
#: selection:marketing.campaign,mode:0
msgid "Test in Realtime"
msgstr "Test in Realtime"
#. module: marketing_campaign
#: selection:marketing.campaign,mode:0
msgid "Test Directly"
msgstr "Test Directly"
#. module: marketing_campaign
#: field:marketing.campaign.activity,report_directory_id:0
msgid "Directory"
msgstr "Directory"
#. module: marketing_campaign
#: field:marketing.campaign.segment,sync_last_date:0
msgid "Latest Synchronization"
msgstr "Latest Synchronization"
#. module: marketing_campaign
#: view:marketing.campaign:0
#: selection:marketing.campaign,state:0
#: view:marketing.campaign.segment:0
#: selection:marketing.campaign.segment,state:0
msgid "Draft"
msgstr "Draft"
#. module: marketing_campaign
#: constraint:ir.ui.menu:0
msgid "Error ! You can not create recursive Menu."
msgstr "Error ! You can not create recursive Menu."
#. module: marketing_campaign
#: field:marketing.campaign.segment,date_run:0
msgid "Launching Date"
msgstr "Launching Date"
#. module: marketing_campaign
#: constraint:ir.model:0
msgid "The Object name must start with x_ and not contain any special character !"
msgstr "The Object name must start with x_ and not contain any special character !"
#. module: marketing_campaign
#: view:marketing.campaign.workitem:0
msgid "Preview"
msgstr "Preview"
#. module: marketing_campaign
#: view:marketing.campaign:0
#: view:marketing.campaign.segment:0
#: view:marketing.campaign.workitem:0
msgid "Status"
msgstr "Status"
#. module: marketing_campaign
#: view:marketing.campaign.segment:0
msgid "Run Date"
msgstr "Run Date"
#. module: marketing_campaign
#: view:marketing.campaign.workitem:0
msgid "Related Resource"
msgstr "Related Resource"
#. module: marketing_campaign
#: selection:campaign.analysis,month:0
msgid "August"
msgstr "August"
#. module: marketing_campaign
#: selection:marketing.campaign,mode:0
msgid "Normal"
msgstr "Normal"
#. module: marketing_campaign
#: help:marketing.campaign.activity,start:0
msgid "This activity is launched when the campaign starts."
msgstr "This activity is launched when the campaign starts."
#. module: marketing_campaign
#: help:marketing.campaign.activity,signal:0
msgid "An activity with a signal can be called programmatically. Be careful, the workitem is always created when a signal is sent"
msgstr "An activity with a signal can be called programmatically. Be careful, the workitem is always created when a signal is sent"
#. module: marketing_campaign
#: selection:campaign.analysis,month:0
msgid "June"
msgstr "June"
#. module: marketing_campaign
#: selection:marketing.campaign.segment,sync_mode:0
msgid "All records (no duplicates)"
msgstr "All records (no duplicates)"
#. module: marketing_campaign
#: view:campaign.analysis:0
#: field:campaign.analysis,date:0
#: view:marketing.campaign.workitem:0
msgid "Date"
msgstr "Date"
#. module: marketing_campaign
#: selection:campaign.analysis,month:0
msgid "November"
msgstr "November"
#. module: marketing_campaign
#: field:marketing.campaign.activity,condition:0
msgid "Condition"
msgstr "Condition"
#. module: marketing_campaign
#: field:marketing.campaign.activity,report_id:0
msgid "The report to generate when this activity is activated"
msgstr "The report to generate when this activity is activated"
#. module: marketing_campaign
#: view:marketing.campaign.workitem:0
#: selection:marketing.campaign.workitem,state:0
msgid "Exception"
msgstr "Exception"
#. module: marketing_campaign
#: selection:campaign.analysis,month:0
msgid "October"
msgstr "October"
#. module: marketing_campaign
#: help:marketing.campaign,fixed_cost:0
msgid "Fixed cost for the campaign (used for campaign analysis), see also variable cost on activities"
msgstr "Fixed cost for the campaign (used for campaign analysis), see also variable cost on activities"
#. module: marketing_campaign
#: selection:campaign.analysis,month:0
msgid "January"
msgstr "January"
#. module: marketing_campaign
#: view:marketing.campaign.workitem:0
#: field:marketing.campaign.workitem,date:0
msgid "Execution Date"
msgstr "Execution Date"
#. module: marketing_campaign
#: model:ir.model,name:marketing_campaign.model_marketing_campaign_workitem
msgid "Campaign Workitem"
msgstr "Campaign Workitem"
#. module: marketing_campaign
#: field:marketing.campaign.segment,ir_filter_id:0
msgid "Filter"
msgstr "Filter"
#. module: marketing_campaign
#: view:marketing.campaign.segment:0
msgid "Synchronize"
msgstr "Synchronize"
#. module: marketing_campaign
#: code:addons/marketing_campaign/marketing_campaign.py:0
#, python-format
msgid "Error"
msgstr "Error"
#. module: marketing_campaign
#: view:marketing.campaign.activity:0
#: field:marketing.campaign.activity,server_action_id:0
#: selection:marketing.campaign.activity,type:0
msgid "Action"
msgstr "Action"
#. module: marketing_campaign
#: code:addons/marketing_campaign/marketing_campaign.py:0
#, python-format
msgid "Automatic transition"
msgstr "Automatic transition"
#. module: marketing_campaign
#: view:res.partner:0
msgid "History"
msgstr "History"
#. module: marketing_campaign
#: help:marketing.campaign,object_id:0
msgid "Choose the model on which you want this campaign to be run"
msgstr "Choose the model on which you want this campaign to be run"
#. module: marketing_campaign
#: model:ir.module.module,shortdesc:marketing_campaign.module_meta_information
msgid "marketing_campaign"
msgstr "marketing_campaign"
#. module: marketing_campaign
#: view:marketing.campaign.workitem:0
msgid "Process"
msgstr "Process"
#. module: marketing_campaign
#: code:addons/marketing_campaign/marketing_campaign.py:0
#: selection:marketing.campaign.transition,trigger:0
#, python-format
msgid "Cosmetic"
msgstr "Cosmetic"
#. module: marketing_campaign
#: help:marketing.campaign.transition,trigger:0
msgid "How is the destination workitem triggered"
msgstr "How is the destination workitem triggered"
#. module: marketing_campaign
#: view:campaign.analysis:0
#: selection:marketing.campaign,state:0
#: selection:marketing.campaign.segment,state:0
#: selection:marketing.campaign.workitem,state:0
msgid "Done"
msgstr "Done"
#. module: marketing_campaign
#: model:ir.model,name:marketing_campaign.model_email_template
msgid "Email Templates for Models"
msgstr "Email Templates for Models"
#. module: marketing_campaign
#: view:marketing.campaign:0
#: view:marketing.campaign.segment:0
msgid "Close"
msgstr "Close"
#. module: marketing_campaign
#: code:addons/marketing_campaign/marketing_campaign.py:0
#, python-format
msgid "The campaign cannot be marked as done before all segments are done"
msgstr "The campaign cannot be marked as done before all segments are done"
#. module: marketing_campaign
#: field:marketing.campaign.workitem,res_id:0
msgid "Resource ID"
msgstr "Resource ID"
#. module: marketing_campaign
#: model:ir.model,name:marketing_campaign.model_marketing_campaign_transition
msgid "Campaign Transition"
msgstr "Campaign Transition"
#. module: marketing_campaign
#: view:campaign.analysis:0
#: view:marketing.campaign.workitem:0
#: selection:marketing.campaign.workitem,state:0
msgid "To Do"
msgstr "To Do"
#. module: marketing_campaign
#: view:marketing.campaign.workitem:0
msgid "Campaign Step"
msgstr "Campaign Step"
#. module: marketing_campaign
#: model:ir.actions.act_window,name:marketing_campaign.action_marketing_campaign_segment_form
#: model:ir.ui.menu,name:marketing_campaign.menu_marketing_campaign_segment_form
#: view:marketing.campaign.segment:0
msgid "Segments"
msgstr "Segments"
#. module: marketing_campaign
#: model:ir.actions.act_window,name:marketing_campaign.act_marketing_campaing_segment_opened
msgid "All Segments"
msgstr "All Segments"
#. module: marketing_campaign
#: view:marketing.campaign.activity:0
msgid "Incoming Transitions"
msgstr "Incoming Transitions"
#. module: marketing_campaign
#: selection:marketing.campaign.activity,type:0
msgid "E-mail"
msgstr "E-mail"
#. module: marketing_campaign
#: code:addons/marketing_campaign/marketing_campaign.py:0
#, python-format
msgid "The campaign cannot be started: the email account is not approved in the email activity '%s'"
msgstr "The campaign cannot be started: the email account is not approved in the email activity '%s'"
#. module: marketing_campaign
#: selection:marketing.campaign.transition,interval_type:0
msgid "Day(s)"
msgstr "Day(s)"
#. module: marketing_campaign
#: field:marketing.campaign,activity_ids:0
#: view:marketing.campaign.activity:0
msgid "Activities"
msgstr "Activities"
#. module: marketing_campaign
#: selection:campaign.analysis,month:0
msgid "May"
msgstr "May"
#. module: marketing_campaign
#: view:marketing.campaign.segment:0
msgid "Modified after Sync"
msgstr "Modified after Sync"
#. module: marketing_campaign
#: view:marketing.campaign:0
#: selection:marketing.campaign,state:0
#: view:marketing.campaign.segment:0
#: selection:marketing.campaign.segment,state:0
msgid "Running"
msgstr "Running"
#. module: marketing_campaign
#: selection:marketing.campaign.activity,type:0
msgid "Paper"
msgstr "Paper"
#. module: marketing_campaign
#: code:addons/marketing_campaign/marketing_campaign.py:0
#, python-format
msgid "After %(interval_nbr)d %(interval_type)s"
msgstr "After %(interval_nbr)d %(interval_type)s"
#. module: marketing_campaign
#: model:ir.model,name:marketing_campaign.model_marketing_campaign
msgid "Marketing Campaign"
msgstr "Marketing Campaign"
#. module: marketing_campaign
#: field:marketing.campaign.segment,date_done:0
msgid "End Date"
msgstr "End Date"
#. module: marketing_campaign
#: selection:campaign.analysis,month:0
msgid "February"
msgstr "February"
#. module: marketing_campaign
#: view:marketing.campaign:0
#: field:marketing.campaign,object_id:0
msgid "Resource"
msgstr "Resource"
#. module: marketing_campaign
#: field:marketing.campaign,name:0
#: field:marketing.campaign.activity,name:0
#: field:marketing.campaign.segment,name:0
#: field:marketing.campaign.transition,name:0
msgid "Name"
msgstr "Name"
#. module: marketing_campaign
#: code:addons/marketing_campaign/marketing_campaign.py:0
#, python-format
msgid "Email Preview"
msgstr "Email Preview"
#. module: marketing_campaign
#: field:marketing.campaign.activity,signal:0
msgid "Signal"
msgstr "Signal"
#. module: marketing_campaign
#: help:marketing.campaign.workitem,date:0
msgid "If date is not set, this workitem have to be run manually"
msgstr "If date is not set, this workitem have to be run manually"
#. module: marketing_campaign
#: code:addons/marketing_campaign/marketing_campaign.py:0
#, python-format
msgid "The campaign cannot be started: there are no activities in it"
msgstr "The campaign cannot be started: there are no activities in it"
#. module: marketing_campaign
#: selection:campaign.analysis,month:0
msgid "April"
msgstr "April"
#. module: marketing_campaign
#: view:marketing.campaign:0
#: field:marketing.campaign,mode:0
msgid "Mode"
msgstr "Mode"
#. module: marketing_campaign
#: field:campaign.analysis,activity_id:0
#: view:marketing.campaign.workitem:0
#: field:marketing.campaign.workitem,activity_id:0
msgid "Activity"
msgstr "Activity"
#. module: marketing_campaign
#: model:ir.actions.act_window,name:marketing_campaign.action_marketing_campaign_workitem
#: model:ir.ui.menu,name:marketing_campaign.menu_action_marketing_campaign_workitem
msgid "Campaign Followup"
msgstr "Campaign Followup"
#. module: marketing_campaign
#: model:ir.model,name:marketing_campaign.model_marketing_campaign_activity
msgid "Campaign Activity"
msgstr "Campaign Activity"
#. module: marketing_campaign
#: field:marketing.campaign.activity,variable_cost:0
msgid "Variable Cost"
msgstr "Variable Cost"
#. module: marketing_campaign
#: selection:marketing.campaign.segment,sync_mode:0
msgid "If record modified after last sync (no duplicates)"
msgstr "If record modified after last sync (no duplicates)"
#. module: marketing_campaign
#: selection:marketing.campaign,mode:0
msgid "With Manual Confirmation"
msgstr "With Manual Confirmation"
#. module: marketing_campaign
#: view:campaign.analysis:0
#: field:campaign.analysis,total_cost:0
msgid "Cost"
msgstr "Cost"
#. module: marketing_campaign
#: view:campaign.analysis:0
#: field:campaign.analysis,year:0
msgid "Year"
msgstr "Year"

View File

@ -91,7 +91,7 @@ class marketing_campaign(osv.osv):
this campaign to be run"),
'partner_field_id': fields.many2one('ir.model.fields', 'Partner Field',
domain="[('model_id', '=', object_id), ('ttype', '=', 'many2one'), ('relation', '=', 'res.partner')]",
help="The generated workitems will be linked to the partner related to the record. If the record is the partner itself left this field empty."),
help="The generated workitems will be linked to the partner related to the record. If the record is the partner itself leave this field empty."),
'mode': fields.selection([('test', 'Test Directly'),
('test_realtime', 'Test in Realtime'),
('manual', 'With Manual Confirmation'),
@ -108,7 +108,7 @@ Normal - the campaign runs normally and automatically sends all emails and repor
'State',),
'activity_ids': fields.one2many('marketing.campaign.activity',
'campaign_id', 'Activities'),
'fixed_cost': fields.float('Fixed Cost', help="Fixed cost for the campaign (used for campaign analysis), see also variable cost on activities"),
'fixed_cost': fields.float('Fixed Cost', help="Fixed cost for running this campaign. You may also specify variable cost and revenue on each campaign activity. Cost and Revenue statistics are included in Campaign Reporting."),
}
_defaults = {
@ -220,20 +220,20 @@ class marketing_campaign_segment(osv.osv):
'object_id': fields.related('campaign_id','object_id',
type='many2one', relation='ir.model',
string='Object'),
'ir_filter_id': fields.many2one('ir.filters', 'Filter', help=""),
'sync_last_date': fields.datetime('Latest Synchronization'),
'ir_filter_id': fields.many2one('ir.filters', 'Filter', help="Filter to select the matching resource records that belong to this segment. New filters can be created and saved using the advanced search on the list view of the Resource"),
'sync_last_date': fields.datetime('Last Synchronization', help="Date on which this segment was synchronized last time (automatically or manually)"),
'sync_mode': fields.selection([('create_date', 'If record created after last sync'),
('write_date', 'If record modified after last sync (no duplicates)'),
('all', 'All records (no duplicates)')],
'Workitem creation mode',
help="Determines when new workitems should be created for records matching a segment."),
help="Determines how new campaign workitems are created for resource records matching this segment. This is used when segments are synchronized manually, or automatically via the scheduled job."),
'state': fields.selection([('draft', 'Draft'),
('running', 'Running'),
('done', 'Done'),
('cancelled', 'Cancelled')],
'State',),
'date_run': fields.datetime('Launching Date'),
'date_done': fields.datetime('End Date'),
'date_run': fields.datetime('Launching Date', help="Initial start date of this segment."),
'date_done': fields.datetime('End Date', help="Date this segment was last closed or cancelled."),
}
_defaults = {
@ -241,6 +241,34 @@ class marketing_campaign_segment(osv.osv):
'sync_mode': lambda *a: 'create_date',
}
def _check_model(self, cr, uid, ids, context=None):
if not context:
context = {}
for obj in self.browse(cr, uid, ids, context=context):
if not obj.ir_filter_id:
return True
if obj.campaign_id.object_id.model != obj.ir_filter_id.model_id:
return False
return True
_constraints = [
(_check_model, _('Model of filter must be same as resource model of Campaign '), ['ir_filter_id,campaign_id']),
]
def onchange_campaign_id(self, cr, uid, ids, campaign_id):
res = {'domain':{'ir_filter_id':[]}}
campaign_pool = self.pool.get('marketing.campaign')
if campaign_id:
campaign = campaign_pool.browse(cr, uid, campaign_id)
model_name = self.pool.get('ir.model').read(cr, uid, [campaign.object_id.id], ['model'])
if model_name:
mod_name = model_name[0]['model']
res['domain'] = {'ir_filter_id': [('model_id', '=', mod_name)]}
res['context'] = {'default_model_id': model_name[0]['model']}
else:
res['value'] = {'ir_filter_id': False}
return res
def state_running_set(self, cr, uid, ids, *args):
segment = self.browse(cr, uid, ids[0])
vals = {'state': 'running'}
@ -325,8 +353,8 @@ class marketing_campaign_activity(osv.osv):
_action_types = [
('email', 'E-mail'),
('paper', 'Paper'),
('action', 'Action'),
('report', 'Report'),
('action', 'Custom Action'),
# TODO implement the subcampaigns.
# TODO implement the subcampaign out. disallow out transitions from
# subcampaign activities ?
@ -346,13 +374,17 @@ class marketing_campaign_activity(osv.osv):
"The expression may use the following [browsable] variables:\n"
" - activity: the campaign activity\n"
" - workitem: the campaign workitem\n"
" - object: the object this campaign item represents\n"
" - resource: the resource object this campaign item represents\n"
" - transitions: list of campaign transitions outgoing from this activity\n"
"...- re: Python regular expression module"),
'type': fields.selection(_action_types, 'Type', required=True,
help="Describe type of action to be performed on the Activity.Eg : Send email,Send paper.."),
'email_template_id': fields.many2one('email.template','The e-mail to send when this activity is activated'),
'report_id': fields.many2one('ir.actions.report.xml', 'The report to generate when this activity is activated', ),
help="""The type of action to execute when an item enters this activity, such as:
- Email: send an email using a predefined email template
- Report: print an existing Report defined on the resource item and save it into a specific directory
- Custom Action: execute a predefined action, e.g. to modify the fields of the resource record
"""),
'email_template_id': fields.many2one('email.template', "Email Template", help='The e-mail to send when this activity is activated'),
'report_id': fields.many2one('ir.actions.report.xml', "Report", help='The report to generate when this activity is activated', ),
'report_directory_id': fields.many2one('document.directory','Directory',
help="This folder is used to store the generated reports"),
'server_action_id': fields.many2one('ir.actions.server', string='Action',
@ -363,11 +395,11 @@ class marketing_campaign_activity(osv.osv):
'from_ids': fields.one2many('marketing.campaign.transition',
'activity_to_id',
'Previous Activities'),
'variable_cost': fields.float('Variable Cost'),
'revenue': fields.float('Revenue'),
'variable_cost': fields.float('Variable Cost', help="Set a variable cost if you consider that every campaign item that has reached this point has entailed a certain cost. You can get cost statistics in the Reporting section"),
'revenue': fields.float('Revenue', help="Set an expected revenue if you consider that every campaign item that has reached this point has generated a certain revenue. You can get revenue statistics in the Reporting section"),
'signal': fields.char('Signal', size=128,
help='An activity with a signal can be called programmatically. Be careful, the workitem is always created when a signal is sent'),
'keep_if_condition_not_met': fields.boolean('Keep as cancelled when condition not met',
'keep_if_condition_not_met': fields.boolean("Don't delete workitems",
help="By activating this option, workitems that aren't executed because the condition is not met are marked as cancelled instead of being deleted.")
}
@ -390,7 +422,7 @@ class marketing_campaign_activity(osv.osv):
return super(marketing_campaign_activity, self).search(cr, uid, args,
offset, limit, order, context, count)
def _process_wi_paper(self, cr, uid, activity, workitem, context=None):
def _process_wi_report(self, cr, uid, activity, workitem, context=None):
service = netsvc.LocalService('report.%s'%activity.report_id.report_name)
(report_data, format) = service.create(cr, uid, [], {}, {})
attach_vals = {
@ -517,23 +549,50 @@ class marketing_campaign_workitem(osv.osv):
res[wi.id] = ng[0][1]
return res
def _resource_search(self, cr, uid, obj, name, args, domain=None, context=None):
"""Returns id of workitem whose resource_name matches with the given name"""
if context is None:
context = {}
if not len(args):
return []
condition = []
final_ids = []
cr.execute("""select w.id, w.res_id, m.model \
from marketing_campaign_workitem w \
left join marketing_campaign_activity a on (a.id=w.activity_id)\
left join marketing_campaign c on (c.id=a.campaign_id)\
left join ir_model m on (m.id=c.object_id)
""")
res = cr.fetchall()
for id, res_id, model in res:
model_pool = self.pool.get(model)
for arg in args:
if arg[1] == 'ilike':
condition.append((model_pool._rec_name, 'ilike', arg[2]))
res_ids = model_pool.search(cr, uid, condition, context=context)
if res_id in res_ids:
final_ids.append(id)
return [('id', 'in', final_ids)]
_columns = {
'segment_id': fields.many2one('marketing.campaign.segment', 'Segment'),
'segment_id': fields.many2one('marketing.campaign.segment', 'Segment', readonly=True),
'activity_id': fields.many2one('marketing.campaign.activity','Activity',
required=True),
required=True, readonly=True),
'campaign_id': fields.related('activity_id', 'campaign_id',
type='many2one', relation='marketing.campaign', string='Campaign', readonly=True),
'object_id': fields.related('activity_id', 'campaign_id', 'object_id',
type='many2one', relation='ir.model', string='Object', select=1),
'res_id': fields.integer('Resource ID', select=1, readonly=1),
'res_name': fields.function(_res_name_get, method=True, string='Resource Name', type="char", size=64),
'date': fields.datetime('Execution Date', help='If date is not set, this workitem have to be run manually'),
'partner_id': fields.many2one('res.partner', 'Partner', select=1),
type='many2one', relation='ir.model', string='Resource', select=1, readonly=True),
'res_id': fields.integer('Resource ID', select=1, readonly=True),
'res_name': fields.function(_res_name_get, method=True, string='Resource Name', fnct_search=_resource_search, type="char", size=64),
'date': fields.datetime('Execution Date', help='If date is not set, this workitem has to be run manually', readonly=True),
'partner_id': fields.many2one('res.partner', 'Partner', select=1, readonly=True),
'state': fields.selection([('todo', 'To Do'),
('exception', 'Exception'), ('done', 'Done'),
('cancelled', 'Cancelled')], 'State'),
('cancelled', 'Cancelled')], 'State', readonly=True),
'error_msg' : fields.text('Error Message')
'error_msg' : fields.text('Error Message', readonly=True)
}
_defaults = {
'state': lambda *a: 'todo',
@ -564,6 +623,7 @@ class marketing_campaign_workitem(osv.osv):
'activity': activity,
'workitem': workitem,
'object': object_id,
'resource': object_id,
'transitions': activity.to_ids,
're': re,
}
@ -688,7 +748,7 @@ class marketing_campaign_workitem(osv.osv):
wi_obj.res_id)
}
elif wi_obj.activity_id.type == 'paper':
elif wi_obj.activity_id.type == 'report':
datas = {
'ids': [wi_obj.res_id],
'model': wi_obj.object_id.model

View File

@ -17,16 +17,25 @@
<field name="arch" type="xml">
<form string="Campaign">
<group colspan="4" col="6">
<field name="name" select="1"/>
<field name="object_id" select="1"/>
<field name="mode"/>
<field name="fixed_cost"/>
<field name="partner_field_id"/>
<group colspan="2" col="2">
<separator string="Campaign" colspan="2" />
<field name="name" select="1"/>
<field name="mode"/>
</group>
<group colspan="2" col="2">
<separator string="Resource" colspan="2" />
<field name="object_id"/>
<field name="partner_field_id"/>
</group>
<group colspan="2" col="2">
<separator string="Cost" colspan="2" />
<field name="fixed_cost"/>
</group>
</group>
<field name="activity_ids" nolabel = "1" colspan="4" default_get="{'default_object_id': object_id}" />
<separator string="Status" colspan="4" />
<separator string="" colspan="4" />
<group col="10" colspan="4">
<field name="state" readonly="1" select="2" nolabel="1"/>
<field name="state" readonly="1" />
<button name="state_running_set" string="Run" states="draft,done,cancelled" icon="gtk-apply"/>
<button name="state_draft_set" string="Set to Draft" states="done,cancelled" icon="gtk-convert"/>
<button name="state_done_set" string="Close" states="running" icon="terp-dialog-close"/>
@ -45,6 +54,7 @@
<field name="name" select="1"/>
<field name="object_id" select="1"/>
<field name="mode"/>
<field name="fixed_cost"/>
<field name="state"/>
</tree>
</field>
@ -125,27 +135,31 @@
<field name="type">form</field>
<field name="arch" type="xml">
<form string="Segments">
<group colspan="4" col="6">
<group colspan="2" col="2">
<separator string="Segment" colspan="4"/>
<field name="name"/>
<field name="campaign_id" select="1"/>
<field name="ir_filter_id" select="1"/>
<field name="object_id" invisible="1" readonly="True"/>
<field name="campaign_id" select="1" on_change="onchange_campaign_id(campaign_id)"/>
</group>
<group colspan="2" col="2">
<separator string="Synchronization" colspan="2"/>
<separator string="Filter" colspan="4"/>
<field name="ir_filter_id" select="1"/>
</group>
<newline/>
<group colspan="2" col="2">
<separator string="Synchronization" colspan="4"/>
<field name="sync_mode" required="True"/>
<field name="sync_last_date"/>
<label string="" colspan="1"/>
<button string="Synchronize" states="running" name="synchroniz" icon="gtk-apply" type="object"/>
<button string="Synchronize" states="running" name="synchroniz" icon="terp-project" type="object"/>
</group>
<group colspan="2" col="2">
<separator string="Dates" colspan="2"/>
<separator string="History" colspan="2"/>
<field name="date_run" readonly="1"/>
<field name="date_done" readonly="1"/>
</group>
<separator string="Status" colspan="4"/>
<group col="10" colspan="4">
<field name="state" readonly="1" select="2" nolabel="1"/>
<separator string="" colspan="4"/>
<group col="6" colspan="4">
<field name="state" readonly="1"/>
<button name="state_running_set" string="Run" states="draft" icon="gtk-apply"/>
<button name="state_done_set" string="Close" states="running" icon="terp-dialog-close"/>
<button name="state_cancel_set" string="Cancel" states="running" icon="terp-gtk-stop"/>
@ -179,8 +193,9 @@
<filter icon="terp-check" string="Running" name="running" domain="[('state','=','running')]"/>
<filter icon="terp-document-new" string="Draft" domain="[('state','=','draft')]"/>
<separator orientation="vertical"/>
<filter icon="terp-go-month" string="Create After Sync" domain="[('sync_mode','=','create_date')]"/>
<filter icon="terp-go-month" string="Modified after Sync" domain="[('sync_mode','=','write_date')]"/>
<filter icon="terp-project" string="Newly Created" domain="[('sync_mode','=','create_date')]"/>
<filter icon="terp-project" string="Newly Modified" domain="[('sync_mode','=','write_date')]"/>
<filter icon="terp-project" string="All" domain="[('sync_mode','=','all')]"/>
<separator orientation="vertical"/>
<field name="name" select="1"/>
<field name="campaign_id" select="1"/>
@ -225,36 +240,38 @@
<field name="type">form</field>
<field name="arch" type="xml">
<form string="Activities">
<field name="object_id" invisible="1"/>
<separator string="Activity Definition" colspan="4"/>
<field name="name" select="1" colspan='4' />
<field name="signal"/>
<field name="start"/>
<field name="variable_cost" select="1"/>
<group colspan='2' col='2'>
<separator string="Activity" colspan="4"/>
<field name="name" select="1" colspan='4' />
<field name="signal" groups="base.group_extended"/>
<field name="start"/>
<field name="object_id" invisible="1"/>
</group>
<group colspan='2' col='2'>
<separator string="Cost / Revenue" colspan="4"/>
<field name="variable_cost"/>
<field name="revenue"/>
</group>
<newline/>
<separator string="Action" colspan="4"/>
<group colspan='4' col='2'>
<separator string="Condition" colspan="4"/>
<field name="condition" widget="char" colspan="2"/>
<field name="keep_if_condition_not_met"/>
</group>
<group colspan='4' col='4'>
<group colspan="4" col="6">
<field name="condition" colspan="5" widget="char"/>
<group col='2'>
<field name="keep_if_condition_not_met" />
</group>
</group>
<field name="type" width='100'/>
<separator string="Action" colspan="4"/>
<field name="type"/>
<group colspan='2' col='1'>
<field name="email_template_id" attrs="{'required':[('type','=','email')], 'invisible':[('type','!=','email')]}"
context="{'default_object_name':object_id}" />
<group attrs="{'invisible':[('type','!=','paper')]}" >
<field name="report_id" attrs="{'required':[('type','=','paper')]}" context="{'object_id':object_id}"/>
<field name="report_directory_id" attrs="{'required':[('type','=','paper')]}" />
<group attrs="{'invisible':[('type','!=','report')]}" >
<field name="report_id" attrs="{'required':[('type','=','report')]}" context="{'object_id':object_id}"/>
<field name="report_directory_id" attrs="{'required':[('type','=','report')]}" />
</group>
<field name="server_action_id" attrs="{'required':[('type','=','action')],'invisible':[('type','!=','action')]}" domain="[('model_id','=',object_id)]" />
</group>
</group>
<newline/>
<group colspan="4" col="2" expand="1">
<group colspan="4" col="2">
<separator string="Transitions" colspan="2"/>
<field name="from_ids" nolabel="1" mode="tree,form" default_get="{'default_activity_to_id': active_id}">
<tree string="Incoming Transitions" editable="bottom">
@ -296,9 +313,9 @@
<field name="arch" type="xml">
<tree string="Activities">
<field name="name" select="1"/>
<field name="start"/>
<field name="condition"/>
<field name="type"/>
<field name="start"/>
</tree>
</field>
</record>
@ -322,6 +339,7 @@
<field name="partner_id"/>
<field name="date"/>
<field name="state"/>
<field name="res_id" invisible="1"/>
<button string="Preview" states="todo" name="preview" icon="gtk-zoom-fit" type="object"/>
<button string="Process" states="todo" name="process" type="object" icon="terp-gtk-go-back-rtl"/>
<button string="Cancel" states="todo" name="button_cancel" type="object" icon="terp-gtk-stop"/>
@ -358,9 +376,9 @@
<separator string="Error Message" colspan="4"/>
<field name="error_msg" nolabel="1" colspan="4"/>
</group>
<separator string="Status" colspan="4"/>
<separator string="" colspan="4"/>
<group colspan="4" col="11">
<field name="state" nolabel="1" readonly="True" select="1"/>
<field name="state" readonly="True"/>
<button string="Reset" states="exception,cancelled" name="button_draft" type="object" icon="gtk-undo"/>
<button string="Process" states="todo" name="process" type="object" icon="terp-gtk-go-back-rtl"/>
<button string="Cancel" states="todo,exception" name="button_cancel" type="object" icon="terp-gtk-stop"/>
@ -375,17 +393,21 @@
<field name="type">search</field>
<field name="arch" type="xml">
<search string="Marketing Campaign Activities">
<filter icon="terp-gtk-go-back-rtl" string="To Do" name = "todo" domain="[('state','=','todo')]"/>
<filter icon="terp-go-today" string="Today" name="today" domain="[('date','&lt;', time.strftime('%%Y-%%m-%%d 23:59:59')), ('date','&gt;=', time.strftime('%%Y-%%m-%%d 00:00:00'))]"/>
<filter icon="terp-gtk-go-back-rtl" string="To Do" name="todo" domain="[('state','=','todo')]"/>
<filter icon="terp-emblem-important" string="Exception" domain="[('state','=','exception')]"/>
<separator orientation="vertical"/>
<field name="segment_id" select="1"/>
<field name="object_id" select="1"/>
<field name="res_name" select="1"/>
<field name="res_id" select="1"/>
<field name="partner_id" select="1"/>
<field name="date" select="1"/>
<newline/>
<group expand="0" string="Group By..." colspan="10" col="12">
<filter string="Segment" name="Segment" icon="terp-stock_symbol-selection" context="{'group_by':'segment_id'}" />
<filter string="Activity" name="Activity" icon="terp-stock_align_left_24" context="{'group_by':'activity_id'}" />
<!--filter string="Campaign" name="campaign" icon="terp-gtk-jump-to-rtl" context="{'group_by':'campaign_id'}" /-->
<filter string="Segment" name="segment" icon="terp-stock_symbol-selection" context="{'group_by':'segment_id'}" />
<filter string="Activity" name="activity" icon="terp-stock_align_left_24" context="{'group_by':'activity_id'}" />
<filter string="Resource" name="resource" icon="terp-accessories-archiver" context="{'group_by':'res_id'}" />
<separator orientation="vertical"/>
<filter string="State" name="State" icon="terp-stock_effects-object-colorize" context="{'group_by':'state'}" />
<separator orientation="vertical"/>
@ -417,5 +439,19 @@
domain="[('campaign_id','=',active_id)]"
/>
<!-- Campaign Followups -->
<act_window domain="[('campaign_id', '=', active_id)]"
id="act_marketing_campaing_followup"
name="Campaign Follow-ups" res_model="marketing.campaign.workitem"
src_model="marketing.campaign" view_mode="tree,form"
view_type="form" />
<!-- Campaign Statistics -->
<act_window domain="[('campaign_id', '=', active_id)]"
id="act_marketing_campaing_stat"
name="Campaign Statistics" res_model="campaign.analysis"
src_model="marketing.campaign" view_mode="tree,form"
view_type="form" />
</data>
</openerp>

View File

@ -38,10 +38,11 @@ class campaign_analysis(osv.osv):
wi_ids = self.pool.get('marketing.campaign.workitem').search(cr, uid,
[('segment_id.campaign_id', '=', ca_obj.campaign_id.id)])
total_cost = ca_obj.activity_id.variable_cost + \
(ca_obj.campaign_id.fixed_cost / len(wi_ids))
((ca_obj.campaign_id.fixed_cost or 0.00) / len(wi_ids))
result[ca_obj.id] = total_cost
return result
_columns = {
'res_id' : fields.integer('Resource', readonly=True),
'year': fields.char('Year', size=4, readonly=True),
'month':fields.selection([('01','January'), ('02','February'),
('03','March'), ('04','April'),('05','May'), ('06','June'),
@ -69,6 +70,7 @@ class campaign_analysis(osv.osv):
create or replace view campaign_analysis as (
select
min(wi.id) as id,
min(wi.res_id) as res_id,
to_char(wi.date::date, 'YYYY') as year,
to_char(wi.date::date, 'MM') as month,
wi.date::date as date,

View File

@ -15,6 +15,7 @@
<field name="segment_id" invisible="1"/>
<field name="partner_id" invisible="1"/>
<field name="country_id" invisible="1"/>
<field name="res_id" invisible="1"/>
<field name="count"/>
<field name="total_cost" string="Cost"/><!-- sum="Cost"/-->
<field name="revenue"/>
@ -35,7 +36,7 @@
<filter icon="terp-go-month"
string="This Month"
domain="[('month','=',time.strftime('%%m'))]"/>
<filter icon="terp-go-month"
<filter icon="terp-go-today"
string="Today"
domain="[('date','=',time.strftime('%%Y/%%m/%%d'))]"/>
<separator orientation="vertical"/>
@ -59,7 +60,9 @@
<group expand="0" string="Group By..." colspan="10" col="12">
<filter string="Campaign" name="Campaign" icon="terp-gtk-jump-to-rtl" context="{'group_by':'campaign_id'}" />
<filter string="Segment" name ="Segment" icon="terp-stock_symbol-selection" context="{'group_by':'segment_id'}" />
<filter string="State" icon="terp-stock_symbol-selection" context="{'group_by':'state'}"/>
<filter string="Activity" name ="activity" icon="terp-stock_align_left_24" context="{'group_by':'activity_id'}" />
<filter string="Resource" icon="terp-accessories-archiver" context="{'group_by':'res_id'}"/>
<filter string="State" icon="terp-stock_effects-object-colorize" context="{'group_by':'state'}"/>
<separator orientation="vertical"/>
<filter string="Partner" icon="terp-personal" context="{'group_by':'partner_id'}"/>
<separator orientation="vertical"/>

View File

@ -191,7 +191,7 @@
<field name="server_action_id" ref="action_dummy"/>
<field model="marketing.campaign" name="campaign_id" ref="marketing_campaign_openerpondemandfreetrial0"/>
<field name="report_directory_id" ref="document_directory_campaign1"/>
<field name="type">paper</field>
<field name="type">report</field>
<field eval="1" name="start"/>
<field name="report_id" ref="mc_crm_lead_demo_report"/>
</record>
@ -220,7 +220,7 @@
<field name="server_action_id" ref="action_dummy"/>
<field model="marketing.campaign" name="campaign_id" ref="marketing_campaign_openerpondemandfreetrial0"/>
<field name="report_directory_id" ref="document_directory_campaign1"/>
<field name="type">paper</field>
<field name="type">report</field>
<field name="report_id" ref="mc_crm_lead_demo_report"/>
</record>

View File

@ -26,11 +26,13 @@
"depends" : ['marketing_campaign'],
"author" : "OpenERP SA",
"category": 'Generic Modules/Marketing',
"description": """
""",
"description": """
This module provides integration of the mailchimp.com marketing campaign and mailing-list service, connecting via Mailchimp's WebServices API.
You can define multiple Mailchimp accounts and then use them as you wish through a new type of activity, providing direct connection to your Mailchimp Lists.""",
'website': 'http://www.openerp.com',
'init_xml': [],
'update_xml': [
"security/ir.model.access.csv",
'marketing_campaign_mailchimp_view.xml',
'wizard/create_list_view.xml',
],

View File

@ -31,14 +31,14 @@
-->
<menuitem name="Tools" id="base.menu_tools" icon="STOCK_PREFERENCES" sequence="28"/>
<menuitem name="Mailchimps" id="menu_action_mailchimp" parent="base.menu_emails" />
<menuitem name="Mailchimp" id="menu_action_mailchimp" parent="base.menu_emails" />
<record model="ir.ui.view" id="view_mailchimp_account_tree">
<field name="name">mailchimp.account.tree</field>
<field name="model">mailchimp.account</field>
<field name="type">tree</field>
<field name="arch" type="xml">
<tree colors="blue:state in ('draft');black:state in ('approved');gray:state in ('cancelled')" string="All Accounts">
<tree colors="blue:state in ('draft');black:state in ('approved');gray:state in ('cancelled')" string="Accounts">
<field name="name"/>
<field name="username" />
<field name="data_center"/>
@ -70,7 +70,7 @@
</record>
<record model="ir.actions.act_window" id="action_mailchimp_account">
<field name="name">All Mailchimp Accounts</field>
<field name="name">Mailchimp Accounts</field>
<field name="type">ir.actions.act_window</field>
<field name="res_model">mailchimp.account</field>
<field name="view_type">form</field>

View File

@ -1,5 +1,4 @@
"id","name","model_id:id","group_id:id","perm_read","perm_write","perm_create","perm_unlink"
"access_mailchimp_account_user","mailchimp.account.user","marketing_campaign_mailchimp.model_mailchimp_account","base.res_groups_email_template_admin",1,1,1,1
"access_mailchimp_account_system","mailchimp.account.user","marketing_campaign_mailchimp.model_mailchimp_account","base.groups_system",1,0,0,0
"access_email_template_account_system","email_template_account_user","marketing_campaign_mailchimp.model_email_template_account","base.res_groups_email_template_admin",1,1,1,1
"access_email_template_campaign","email_template_campaign","model_email_template","base.res_groups_email_template_admin",1,1,1,1
"access_mailchimp_account_system","mailchimp.account.user","marketing_campaign_mailchimp.model_mailchimp_account","base.res_groups_email_template_admin",1,0,0,0
"access_mailchimp_account_user","mailchimp_account_user","model_mailchimp_account","base.res_groups_email_template_admin",1,1,1,1

1 id name model_id:id group_id:id perm_read perm_write perm_create perm_unlink
2 access_mailchimp_account_user mailchimp.account.user marketing_campaign_mailchimp.model_mailchimp_account base.res_groups_email_template_admin 1 1 1 1
3 access_mailchimp_account_system mailchimp.account.user marketing_campaign_mailchimp.model_mailchimp_account base.groups_system base.res_groups_email_template_admin 1 0 0 0
4 access_email_template_account_system access_mailchimp_account_user email_template_account_user mailchimp_account_user marketing_campaign_mailchimp.model_email_template_account model_mailchimp_account base.res_groups_email_template_admin 1 1 1 1
access_email_template_campaign email_template_campaign model_email_template base.res_groups_email_template_admin 1 1 1 1

View File

@ -5,7 +5,8 @@
<field name="model">create.list</field>
<field name="type">form</field>
<field name="arch" type="xml">
<form string="Update List">
<form string="Update List Manually">
<separator string="Update List Manually" colspan="4"/>
<field name="mailchimp_account_id" on_change = "onchange_mailchimp_account_id(mailchimp_account_id,action)"/>
<field name="list_name" />
<newline/>
@ -19,14 +20,18 @@
</field>
</record>
<record id="action_create_list" model="ir.actions.act_window">
<field name="name">Update List</field>
<field name="name">Manual Mailchimp List Update</field>
<field name="type">ir.actions.act_window</field>
<field name="res_model">create.list</field>
<field name="view_type">form</field>
<field name="view_id" ref="view_create_list"/>
<field name="target">new</field>
</record>
<menuitem id="menu_action_mailchimp_create_list" parent="menu_action_mailchimp" action="action_create_list" sequence="40"/>
<menuitem id="menu_action_mailchimp_create_list"
name="Manual Mailchimp List Update"
parent="menu_action_mailchimp" action="action_create_list"
sequence="40" />
</data>
</data>
</openerp>

View File

@ -31,14 +31,14 @@
work done on tasks, eso. It is able to render planning, order tasks, eso.
Dashboard for project members that includes:
* List of my open tasks
* List of messages
* Members list of project
* Issues
""",
"init_xml": [],
"update_xml": [
"security/project_security.xml",
"wizard/project_task_delegate_view.xml",
"wizard/project_task_close_view.xml",
"wizard/project_task_reevaluate_view.xml",
"security/ir.model.access.csv",
"project_data.xml",
"project_view.xml",
@ -46,7 +46,6 @@ work done on tasks, eso. It is able to render planning, order tasks, eso.
"project_installer.xml",
"res_partner_view.xml",
"report/project_report_view.xml",
"wizard/project_close_task_view.xml",
"board_project_view.xml",
'board_project_manager_view.xml'
],

View File

@ -78,17 +78,6 @@
<field name="view_mode">tree,form</field>
<field name="domain">[('type','=','Project')]</field>
</record>
<!--Actions for deshboard -->
<record id="action_view_project_editable_messages_tree" model="ir.actions.act_window">
<field name="name">Messages</field>
<field name="res_model">project.message</field>
<field name="view_type">form</field>
<field name="view_mode">tree,form</field>
<field name="view_id" ref="project.view_project_message_tree"/>
</record>
<record id="board_project_form" model="ir.ui.view">
<field name="name">board.project.form</field>
<field name="model">board.board</field>

View File

@ -25,6 +25,7 @@ from datetime import datetime, date
from tools.translate import _
from osv import fields, osv
from tools import email_send as email
class project_task_type(osv.osv):
_name = 'project.task.type'
@ -171,7 +172,7 @@ class project(osv.osv):
'planned_hours': fields.function(_progress_rate, multi="progress", method=True, string='Planned Time', help="Sum of planned hours of all tasks related to this project and its child projects."),
'effective_hours': fields.function(_progress_rate, multi="progress", method=True, string='Time Spent', help="Sum of spent hours of all tasks related to this project and its child projects."),
'total_hours': fields.function(_progress_rate, multi="progress", method=True, string='Total Time', help="Sum of total hours of all tasks related to this project and its child projects."),
'progress_rate': fields.function(_progress_rate, multi="progress", method=True, string='Progress', type='float', help="Percent of tasks closed according to the total of tasks todo."),
'progress_rate': fields.function(_progress_rate, multi="progress", method=True, string='Progress', type='float', group_operator="avg", help="Percent of tasks closed according to the total of tasks todo."),
'warn_customer': fields.boolean('Warn Partner', help="If you check this, the user will have a popup when closing a task that propose a message to send by email to the customer.", states={'close':[('readonly',True)], 'cancelled':[('readonly',True)]}),
'warn_header': fields.text('Mail Header', help="Header added at the beginning of the email for the warning message sent to the customer when a task is closed.", states={'close':[('readonly',True)], 'cancelled':[('readonly',True)]}),
'warn_footer': fields.text('Mail Footer', help="Footer added at the beginning of the email for the warning message sent to the customer when a task is closed.", states={'close':[('readonly',True)], 'cancelled':[('readonly',True)]}),
@ -427,7 +428,7 @@ class task(osv.osv):
'effective_hours': fields.function(_hours_get, method=True, string='Hours Spent', multi='hours', store=True, help="Computed using the sum of the task work done."),
'remaining_hours': fields.float('Remaining Hours', digits=(16,2), help="Total remaining time, can be re-estimated periodically by the assignee of the task."),
'total_hours': fields.function(_hours_get, method=True, string='Total Hours', multi='hours', store=True, help="Computed as: Time Spent + Remaining Time."),
'progress': fields.function(_hours_get, method=True, string='Progress (%)', multi='hours', store=True, help="Computed as: Time Spent / Total Time."),
'progress': fields.function(_hours_get, method=True, string='Progress (%)', multi='hours', group_operator="avg", store=True, help="Computed as: Time Spent / Total Time."),
'delay_hours': fields.function(_hours_get, method=True, string='Delay Hours', multi='hours', store=True, help="Computed as difference of the time estimated by the project manager and the real time to close the task."),
'user_id': fields.many2one('res.users', 'Assigned to'),
@ -486,18 +487,17 @@ class task(osv.osv):
res['fields'][f]['string'] = res['fields'][f]['string'].replace('Hours',tm)
return res
def do_close(self, cr, uid, ids, *args):
mail_send = False
mod_obj = self.pool.get('ir.model.data')
def do_close(self, cr, uid, ids, context=None):
"""
Close Task
"""
if context is None:
context = {}
request = self.pool.get('res.request')
tasks = self.browse(cr, uid, ids)
task_id = ids[0]
cntx = {}
if len(args):
cntx = args[0]
for task in tasks:
for task in self.browse(cr, uid, ids, context=context):
project = task.project_id
if project:
# Send request to project manager
if project.warn_manager and project.user_id and (project.user_id.id != uid):
request.create(cr, uid, {
'name': _("Task '%s' closed") % task.name,
@ -508,12 +508,7 @@ class task(osv.osv):
'ref_doc1': 'project.task,%d'% (task.id,),
'ref_doc2': 'project.project,%d'% (project.id,),
})
elif (project.warn_manager or project.warn_customer) and cntx.get('mail_send',True):
cntx.update({'send_manager': project.warn_manager, 'send_partner': project.warn_customer})
mail_send = True
message = _('Task ') + " '" + task.name + "' "+ _("is Done.")
self.log(cr, uid, task.id, message)
for parent_id in task.parent_ids:
if parent_id.state in ('pending','draft'):
reopen = True
@ -522,29 +517,16 @@ class task(osv.osv):
reopen = False
if reopen:
self.do_reopen(cr, uid, [parent_id.id])
if mail_send:
model_data_ids = mod_obj.search(cr,uid,[('model','=','ir.ui.view'),('name','=','view_project_close_task')])
resource_id = mod_obj.read(cr, uid, model_data_ids, fields=['res_id'])[0]['res_id']
cntx.update({'task_id': task_id})
return {
'name': _('Email Send to Customer'),
'view_type': 'form',
'context': cntx, # improve me
'view_mode': 'tree,form',
'res_model': 'close.task',
'views': [(resource_id,'form')],
'type': 'ir.actions.act_window',
'target': 'new',
'nodestroy': True
}
else:
self.write(cr, uid, [task_id], {'state': 'done', 'date_end':time.strftime('%Y-%m-%d %H:%M:%S'), 'remaining_hours': 0.0})
return False
self.write(cr, uid, [task.id], {'state': 'done', 'date_end':time.strftime('%Y-%m-%d %H:%M:%S'), 'remaining_hours': 0.0})
message = _('Task ') + " '" + task.name + "' "+ _("is Done.")
self.log(cr, uid, task.id, message)
return True
def do_reopen(self, cr, uid, ids, *args):
def do_reopen(self, cr, uid, ids, context=None):
if context is None:
context = {}
request = self.pool.get('res.request')
tasks = self.browse(cr, uid, ids)
for task in tasks:
for task in self.browse(cr, uid, ids, context=context):
project = task.project_id
if project and project.warn_manager and project.user_id.id and (project.user_id.id != uid):
request.create(cr, uid, {
@ -592,6 +574,40 @@ class task(osv.osv):
self.write(cr, uid, ids, {'state': 'draft'})
return True
def do_delegate(self, cr, uid, task_id, delegate_data={}, context=None):
"""
Delegate Task to another users.
"""
if context is None:
context = {}
task = self.browse(cr, uid, task_id, context=context)
new_task_id = self.copy(cr, uid, task.id, {
'name': delegate_data['name'],
'user_id': delegate_data['user_id'],
'planned_hours': delegate_data['planned_hours'],
'remaining_hours': delegate_data['planned_hours'],
'parent_ids': [(6, 0, [task.id])],
'state': 'draft',
'description': delegate_data['new_task_description'] or '',
'child_ids': [],
'work_ids': []
}, context)
newname = delegate_data['prefix'] or ''
self.write(cr, uid, [task.id], {
'remaining_hours': delegate_data['planned_hours_me'],
'planned_hours': delegate_data['planned_hours_me'] + (task.effective_hours or 0.0),
'name': newname,
}, context)
if delegate_data['state'] == 'pending':
self.do_pending(cr, uid, [task.id], context)
else:
self.do_close(cr, uid, [task.id], context)
user_pool = self.pool.get('res.users')
delegrate_user = user_pool.browse(cr, uid, delegate_data['user_id'], context=context)
message = _('Task ') + " '" + delegate_data['name'] + "' "+ _("is Delegated to User:") +" '"+ delegrate_user.name +"' "
self.log(cr, uid, task.id, message)
return True
def do_pending(self, cr, uid, ids, *args):
self.write(cr, uid, ids, {'state': 'pending'})
for (id, name) in self.name_get(cr, uid, ids):
@ -691,105 +707,6 @@ class project_work(osv.osv):
project_work()
class config_compute_remaining(osv.osv_memory):
_name='config.compute.remaining'
def _get_remaining(self,cr, uid, context=None):
if context and 'active_id' in context:
return self.pool.get('project.task').browse(cr, uid, context['active_id'], context=context).remaining_hours
return False
_columns = {
'remaining_hours' : fields.float('Remaining Hours', digits=(16,2), help="Put here the remaining hours required to close the task."),
}
_defaults = {
'remaining_hours': _get_remaining
}
def fields_view_get(self, cr, uid, view_id=None, view_type='form', context=None, toolbar=False, submenu=False):
users_obj = self.pool.get('res.users')
obj_tm = users_obj.browse(cr, uid, uid, context).company_id.project_time_mode_id
tm = obj_tm and obj_tm.name or 'Hours'
res = super(config_compute_remaining, self).fields_view_get(cr, uid, view_id, view_type, context, toolbar, submenu=submenu)
if tm in ['Hours','Hour']:
return res
eview = etree.fromstring(res['arch'])
def _check_rec(eview):
if eview.attrib.get('widget','') == 'float_time':
eview.set('widget','float')
for child in eview:
_check_rec(child)
return True
_check_rec(eview)
res['arch'] = etree.tostring(eview)
for f in res['fields']:
if 'Hours' in res['fields'][f]['string']:
res['fields'][f]['string'] = res['fields'][f]['string'].replace('Hours',tm)
return res
def compute_hours(self, cr, uid, ids, context=None):
if context is None:
context = {}
task_obj = self.pool.get('project.task')
request = self.pool.get('res.request')
if 'active_id' in context:
remaining_hrs = self.browse(cr,uid,ids)[0].remaining_hours
task_obj.write(cr,uid,context['active_id'],{'remaining_hours':remaining_hrs})
if context.get('button_reactivate', False):
tasks = task_obj.browse(cr, uid, [context['active_id']], context=context)
for task in tasks:
project = task.project_id
if project and project.warn_manager and project.user_id.id and (project.user_id.id != uid):
request.create(cr, uid, {
'name': _("Task '%s' set in progress") % task.name,
'state': 'waiting',
'act_from': uid,
'act_to': project.user_id.id,
'ref_partner_id': task.partner_id.id,
'ref_doc1': 'project.task,%d' % task.id,
'ref_doc2': 'project.project,%d' % project.id,
})
task_obj.write(cr, uid, [task.id], {'state': 'open'})
return {
'type': 'ir.actions.act_window_close',
}
config_compute_remaining()
class message(osv.osv):
_name = "project.message"
_description = "Message"
_columns = {
'subject': fields.char('Subject', size=128, required="True"),
'project_id': fields.many2one('project.project', 'Project', ondelete='cascade'),
'date': fields.date('Date', required=1),
'user_id': fields.many2one('res.users', 'User', required="True"),
'description': fields.text('Description'),
}
def _default_project(self, cr, uid, context=None):
if context is None:
context = {}
if 'project_id' in context and context['project_id']:
return int(context['project_id'])
return False
_defaults = {
'user_id': lambda self,cr,uid,ctx: uid,
'date': time.strftime('%Y-%m-%d'),
'project_id': _default_project
}
message()
class account_analytic_account(osv.osv):
_inherit = 'account.analytic.account'

View File

@ -254,15 +254,5 @@
<field name="project_id" ref="project_project_22"/>
<field name="name">Latest in house tests</field>
</record>
<record id="project_message_1" model="project.message">
<field name="project_id" ref="project.project_project_23"/>
<field name="user_id" ref="base.user_root"/>
<field name="description">Follow the procedure of Configuration wizard.
- Add all required modules
- Add chat of accounts
- Create Users</field>
<field name="subject">Configuration steps</field>
</record>
</data>
</openerp>

View File

@ -109,7 +109,7 @@
</group>
<newline />
<group expand="0" string="Group By..." colspan="4" col="20" groups="base.group_extended">
<filter string="User" name="Users" icon="terp-personal" domain = "[]" context="{'group_by':'user_id'}"/>
<filter string="Manager" name="Manager" icon="terp-personal" domain = "[]" context="{'group_by':'user_id'}"/>
<filter string="Partner" name="Partner" icon="terp-personal" domain = "[]" context="{'group_by':'partner_id'}"/>
<separator orientation="vertical"/>
<filter string="Parent" name="Parent" icon="terp-folder-blue" domain = "[]" context="{'group_by':'parent_id'}"/>
@ -189,33 +189,6 @@
</field>
</record>
<record id="view_config_compute_remaining" model="ir.ui.view">
<field name="name">Compute Remaining Hours </field>
<field name="model">config.compute.remaining</field>
<field name="type">form</field>
<field name="arch" type="xml">
<form string="Reevaluate Hours">
<separator colspan="4" string="Change Remaining Time"/>
<newline/>
<field name="remaining_hours" widget="float_time"/>
<separator string="" colspan="4"/>
<group col="4" colspan="4">
<button icon="gtk-cancel" special="cancel" string="Cancel"/>
<button icon="gtk-apply" name="compute_hours" string="Update" type="object" default_focus="1"/>
</group>
</form>
</field>
</record>
<record id="action_config_compute_remaining" model="ir.actions.act_window">
<field name="name">Compute Remaining Hours</field>
<field name="type">ir.actions.act_window</field>
<field name="res_model">config.compute.remaining</field>
<field name="view_type">form</field>
<field name="view_mode">form</field>
<field name="target">new</field>
</record>
<!-- Task -->
<record id="view_task_form2" model="ir.ui.view">
<field name="name">project.task.form</field>
@ -244,7 +217,7 @@
</group>
<group col="3" colspan="2">
<field name="remaining_hours" widget="float_time" attrs="{'readonly':[('state','!=','draft')]}" colspan="2"/>
<button name="%(action_config_compute_remaining)d" string="Reevaluate" type="action" colspan="1" target="new" states="open,pending" icon="gtk-edit"/>
<button name="%(action_project_task_reevaluate)d" string="Reevaluate" type="action" colspan="1" target="new" states="open,pending" icon="gtk-edit"/>
<field name="delay_hours" widget="float_time"/>
</group>
@ -263,10 +236,10 @@
<field name="state" select="1"/>
<button name="do_draft" states="open" string="Draft" type="object" icon="gtk-indent"/>
<button name="do_open" states="pending,draft" string="Start Task" type="object" icon="gtk-execute"/>
<button name="%(action_config_compute_remaining)d" states="done,cancelled" string="Reactivate" type="action" icon="gtk-convert" context="{'button_reactivate':True}" />
<button name="%(action_project_task_reevaluate)d" states="done,cancelled" string="Reactivate" type="action" icon="gtk-convert" context="{'button_reactivate':True}" />
<button name="do_pending" states="open" string="Pending" type="object" icon="gtk-media-pause"/>
<button groups="base.group_extended" name="%(action_project_task_delegate)d" states="pending,open" string="Delegate" type="action" icon="gtk-sort-descending"/>
<button name="do_close" states="pending,open" string="Done" type="object" icon="gtk-apply"/>
<button name="%(action_project_task_close)d" states="pending,open" string="Done" type="action" icon="gtk-apply"/>
<button name="do_cancel" states="draft,open,pending" string="Cancel" type="object" icon="gtk-cancel"/>
</group>
</page>
@ -343,7 +316,7 @@
<field name="state" invisible="context.get('set_visible',False)"/>
<button name="do_open" states="pending,draft,done,cancel" string="Start Task" type="object" icon="gtk-execute" help="For changing to open state" invisible="context.get('set_visible',False)"/>
<button groups="base.group_extended" name="%(action_project_task_delegate)d" states="pending,open,draft" string="Delegate" type="action" icon="gtk-sort-descending" help="For changing to delegate state"/>
<button name="do_close" states="draft,pending,open" string="Done" type="object" icon="gtk-apply" help="For changing to done state"/>
<button name="%(action_project_task_close)d" states="draft,pending,open" string="Done" type="action" icon="gtk-apply" help="For changing to done state"/>
<button name="do_cancel" states="draft,open,pending" string="Cancel" type="object" icon="gtk-cancel" help="For cancelling the task"/>
</tree>
</field>
@ -421,7 +394,7 @@
<separator orientation="vertical"/>
<filter string="Project" name="group_project_id" icon="terp-folder-blue" domain="[]" context="{'group_by':'project_id'}"/>
<separator orientation="vertical"/>
<filter string="Stage" name="group_stage_id" icon="terp-stage" domain="[]" context="{'group_by':'type_id'}"/>
<filter string="Stages" name="group_stage_id" icon="terp-stage" domain="[]" context="{'group_by':'type_id'}"/>
<filter string="State" name="group_state" icon="terp-stock_effects-object-colorize" domain="[]" context="{'group_by':'state'}"/>
<separator orientation="vertical"/>
<filter string="Start Date" icon="terp-go-month" domain="[]" context="{'group_by':'date_start'}"/>
@ -564,82 +537,7 @@ Issues like bugs in a system, client complain, materials breakdown are collected
</page>
</field>
</record>
<!--- Messages-->
<record id="view_project_message_form" model="ir.ui.view">
<field name="name">project.message.form</field>
<field name="model">project.message</field>
<field name="type">form</field>
<field name="arch" type="xml">
<form string="Messages">
<group colspan="6">
<field name="subject" select="1"/>
<field name="project_id"/>
<field name="user_id" select="1"/>
<field name="date"/>
</group>
<separator string="Description" colspan="4"/>
<field name="description" nolabel="1" colspan="4"/>
</form>
</field>
</record>
<record id="view_project_message_tree" model="ir.ui.view">
<field name="name">project.message.tree</field>
<field name="model">project.message</field>
<field name="type">tree</field>
<field name="arch" type="xml">
<tree string="Messages">
<field name="date" select="1"/>
<field name="subject" select="1"/>
<field name="project_id" select="1"/>
<field name="user_id" select="1"/>
</tree>
</field>
</record>
<record id="view_project_message_search" model="ir.ui.view">
<field name="name">project.message.search</field>
<field name="model">project.message</field>
<field name="type">search</field>
<field name="arch" type="xml">
<search string="Messages">
<group col="20" colspan="4">
<filter domain="[('date','&gt;=',time.strftime('%%Y-%%m-01'))]" icon="terp-go-month" string="This Month" />
<filter domain="[('date', '=', time.strftime('%%Y-%%m-%%d'))]" icon="terp-go-today" string="Today" />
<separator orientation="vertical"/>
<field name="subject"/>
<field name="project_id" select="1"/>
<field name="user_id" select="1"/>
</group>
<newline/>
<group expand="0" string="Group By..." colspan="4" col="20">
<filter string="Project" icon="terp-folder-blue" domain="[]" context="{'group_by':'project_id'}"/>
<filter string="User" icon="terp-personal" domain="[]" context="{'group_by':'user_id'}"/>
<filter string="Date" icon="terp-go-month" domain="[]" context="{'group_by':'date'}"/>
</group>
</search>
</field>
</record>
<record id="action_view_project_messages_tree" model="ir.actions.act_window">
<field name="name">Project Messages</field>
<field name="res_model">project.message</field>
<field name="view_type">form</field>
<field name="view_mode">tree,form</field>
<field name="view_id" ref="view_project_message_tree"/>
<field name="context">{"search_default_project_id":project_id, "search_default_user_id":uid}</field>
<field name="search_view_id" ref="view_project_message_search"/>
<field name="help">An in-project messagery system permits an efficient and trackable communication between project members. The messages are kept in the system and can then be used for post-analysis.</field>
</record>
<menuitem action="action_view_project_messages_tree" id="menu_message_tree" parent="menu_project_management" sequence="11"/>
<act_window domain="[('user_id', '=', active_id),('state', '&lt;&gt;', 'cancelled'),('state', '&lt;&gt;', 'done')]" id="act_res_users_2_project_task_opened" name="Assigned tasks" res_model="project.task" src_model="res.users" view_mode="tree,form,gantt,calendar,graph" view_type="form"/>
<act_window domain="[('user_id', '=', active_id),('date', '&gt;=', time.strftime('%Y-%m-01'))]" id="act_res_users_2_project_task_work_month" name="Month works" res_model="project.task.work" src_model="res.users" view_mode="tree,form" view_type="form"/>
<act_window domain="[('project_id', '=', active_id)]" id="act_project_messages" name="Messages" res_model="project.message" src_model="project.project"/>
<act_window domain="[('user_id', '=', active_id),('state', '&lt;&gt;', 'cancelled'),('state', '&lt;&gt;', 'done')]" id="act_res_users_2_project_task_opened" name="Assigned tasks" res_model="project.task" src_model="res.users" view_mode="tree,form,gantt,calendar,graph" view_type="form"/>
<act_window domain="[('user_id', '=', active_id),('date', '&gt;=', time.strftime('%Y-%m-01'))]" id="act_res_users_2_project_task_work_month" name="Month works" res_model="project.task.work" src_model="res.users" view_mode="tree,form" view_type="form"/>
</data>
</openerp>

View File

@ -1,15 +1,14 @@
"id","name","model_id:id","group_id:id","perm_read","perm_write","perm_create","perm_unlink"
"access_project_project_manager","project.project manager","model_project_project","project.group_project_manager",1,0,0,0
"access_project_project_manager","project.project manager","model_project_project","project.group_project_manager",1,1,1,1
"access_account_analytic_account_manager","account.analytic.account","analytic.model_account_analytic_account","project.group_project_manager",1,0,0,0
"access_project_project","project.project","model_project_project","project.group_project_user",1,1,1,1
"access_account_analytic_account","account.analytic.account","analytic.model_account_analytic_account","project.group_project_user",1,1,1,1
"access_project_task_type_user","project.task.type user","model_project_task_type","project.group_project_user",1,1,1,1
"access_project_task_type","project.task.type","model_project_task_type","project.group_project_manager",1,1,1,1
"access_project_task_manager","project.task manager","model_project_task","project.group_project_manager",1,0,0,0
"access_project_task_manager","project.task manager","model_project_task","project.group_project_manager",1,1,1,1
"access_project_task","project.task","model_project_task","project.group_project_user",1,1,1,1
"access_project_task_work","project.task.work","model_project_task_work","project.group_project_user",1,1,1,1
"access_project_task_work_manager","project.task.work.manager","model_project_task_work","project.group_project_manager",1,1,1,1
"access_project_message","project.message","model_project_message","project.group_project_user",1,1,1,1
"access_report_project_task_user","report.project.task.user","model_report_project_task_user","project.group_project_manager",1,1,1,1
"access_project_vs_hours","project.vs.hours","model_project_vs_hours","project.group_project_user",1,1,1,1
"access_task_by_days","task.by.days","model_task_by_days","project.group_project_user",1,1,1,1
@ -19,8 +18,6 @@
"access_partner_address_task manager","base.res.partner.address manager","base.model_res_partner_address","project.group_project_manager",1,0,0,0
"access_task_on_partner","project.task on partners","model_project_task","base.group_user",1,0,0,0
"access_project_on_partner","project.project on partners","model_project_project","base.group_user",1,0,0,0
"access_project_message_manager","project.message manager","model_project_message","project.group_project_manager",1,0,0,0
"access_project_message_system","project.message system","model_project_message","base.group_system",1,0,0,0
"access_project_task_system","project.task system","model_project_task","base.group_system",1,0,0,0
"access_project_project_system","project.project system","model_project_project","base.group_system",1,1,1,1
"access_project_task_work_system","project.task.work system","model_project_task_work","base.group_system",1,0,0,0

1 id name model_id:id group_id:id perm_read perm_write perm_create perm_unlink
2 access_project_project_manager project.project manager model_project_project project.group_project_manager 1 0 1 0 1 0 1
3 access_account_analytic_account_manager account.analytic.account analytic.model_account_analytic_account project.group_project_manager 1 0 0 0
4 access_project_project project.project model_project_project project.group_project_user 1 1 1 1
5 access_account_analytic_account account.analytic.account analytic.model_account_analytic_account project.group_project_user 1 1 1 1
6 access_project_task_type_user project.task.type user model_project_task_type project.group_project_user 1 1 1 1
7 access_project_task_type project.task.type model_project_task_type project.group_project_manager 1 1 1 1
8 access_project_task_manager project.task manager model_project_task project.group_project_manager 1 0 1 0 1 0 1
9 access_project_task project.task model_project_task project.group_project_user 1 1 1 1
10 access_project_task_work project.task.work model_project_task_work project.group_project_user 1 1 1 1
11 access_project_task_work_manager project.task.work.manager model_project_task_work project.group_project_manager 1 1 1 1
access_project_message project.message model_project_message project.group_project_user 1 1 1 1
12 access_report_project_task_user report.project.task.user model_report_project_task_user project.group_project_manager 1 1 1 1
13 access_project_vs_hours project.vs.hours model_project_vs_hours project.group_project_user 1 1 1 1
14 access_task_by_days task.by.days model_task_by_days project.group_project_user 1 1 1 1
18 access_partner_address_task manager base.res.partner.address manager base.model_res_partner_address project.group_project_manager 1 0 0 0
19 access_task_on_partner project.task on partners model_project_task base.group_user 1 0 0 0
20 access_project_on_partner project.project on partners model_project_project base.group_user 1 0 0 0
access_project_message_manager project.message manager model_project_message project.group_project_manager 1 0 0 0
access_project_message_system project.message system model_project_message base.group_system 1 0 0 0
21 access_project_task_system project.task system model_project_task base.group_system 1 0 0 0
22 access_project_project_system project.project system model_project_project base.group_system 1 1 1 1
23 access_project_task_work_system project.task.work system model_project_task_work base.group_system 1 0 0 0

View File

@ -122,12 +122,12 @@
-
Now in order to reactivate the task 'Technical Training', i click on the "Reactivate" button and fill the remaining hour field
-
!record {model: config.compute.remaining, id: project_task_technicaltraining_remainingwiz0}:
!record {model: project.task.reevaluate, id: project_task_technicaltraining_remainingwiz0}:
remaining_hours: 30.0
- |
I click the apply button
-
!python {model: config.compute.remaining}: |
!python {model: project.task.reevaluate}: |
self.compute_hours(cr, uid, [ref('project_task_technicaltraining_remainingwiz0')], {'active_id': ref("project_task_technicaltraining0"),'button_reactivate': True})
- |
Check if task 'Technical Training' in open state and for other initial values
@ -193,12 +193,12 @@
-
Set remaining hours of 10 hours for reevaluating the task
-
!record {model: config.compute.remaining, id: config_compute_remaining_0}:
!record {model: project.task.reevaluate, id: config_compute_remaining_0}:
remaining_hours: 10.0
-
Reevaluate the task
-
!python {model: config.compute.remaining}: |
!python {model: project.task.reevaluate}: |
self.compute_hours(cr, uid, [ref("config_compute_remaining_0")], {"lang": "en_US",
"project_id": False, "tz": False, "active_model": "project.task", "search_default_project_id":
False, "search_default_user_id": 1, "search_default_current": 1, "active_ids":
@ -248,12 +248,12 @@
-
Reactivate task
-
!record {model: config.compute.remaining, id: config_compute_remaining_1}:
!record {model: project.task.reevaluate, id: config_compute_remaining_1}:
remaining_hours: 10.0
-
Reevaluate the task with 10 hours remaining
-
!python {model: config.compute.remaining}: |
!python {model: project.task.reevaluate}: |
self.compute_hours(cr, uid, [ref("config_compute_remaining_1")], {"lang": "en_US",
"project_id": False, "tz": False, "button_reactivate": True, "active_model":
"project.task", "search_default_project_id": False, "search_default_user_id":

View File

@ -61,7 +61,7 @@
Validating the delegate task
-
!python {model: project.task.delegate}: |
self.validate(cr, uid, [ref("project_task_publish_book_delegate")],
self.delegate(cr, uid, [ref("project_task_publish_book_delegate")],
{"lang": "en_US", "active_model": "project.task", "tz": False, "record_id":
4, "active_ids": [ref("project_task_publish_book")], "active_id": ref("project_task_publish_book"),
})
@ -227,4 +227,4 @@
Parent task 'Develop book for Technical and Functional reference' must be now in open state
-
!assert {model: project.task, id: project_task_documentation_book, severity: error, string: Task is in done state}:
- state == "open"
- state == "open"

View File

@ -19,8 +19,9 @@
#
##############################################################################
import project_close_task
import project_task_close
import project_task_delegate
import project_task_reevaluate
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

View File

@ -1,133 +0,0 @@
# -*- coding: utf-8 -*-
##############################################################################
#
# OpenERP, Open Source Management Solution
# Copyright (C) 2004-2010 Tiny SPRL (<http://tiny.be>).
#
# 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 <http://www.gnu.org/licenses/>.
#
##############################################################################
import time
from osv import fields, osv
from tools.translate import _
from tools import email_send as email
class project_close_task(osv.osv_memory):
"""
Close Task
"""
_name = "close.task"
_description = "Project Close Task"
_columns = {
'manager_email': fields.char('Manager E-Mail ID', size=64, help="Email Address of Project's Manager"),
'partner_email': fields.char('Partner E-Mail ID', size=64, help="Email Address of Partner"),
'description': fields.text('Description'),
}
def _get_manager_email(self, cr, uid, context=None):
if context is None:
context = {}
email = ''
if context.get('send_manager', False) and ('task_id' in context):
project_id = self.pool.get('project.task').read(cr, uid, context['task_id'], ['project_id'])['project_id'][0]
project = self.pool.get('project.project').browse(cr, uid, project_id)
manager_id = project.user_id or False
if manager_id and manager_id.user_email:
email = manager_id.user_email
return email
def _get_partner_email(self, cr, uid, context=None):
if context is None:
context = {}
email = ''
if context.get('send_partner', False) and ('task_id' in context):
task = self.pool.get('project.task').browse(cr, uid, context['task_id'])
partner_id = task.partner_id or task.project_id.partner_id
if partner_id and len(partner_id.address) and partner_id.address[0].email:
email = partner_id.address[0].email
return email
def _get_desc(self, cr, uid, context=None):
if context is None:
context = {}
if 'task_id' in context:
task = self.pool.get('project.task').browse(cr, uid, context['task_id'])
return task.description or task.name
return ''
_defaults = {
'manager_email': _get_manager_email,
'partner_email': _get_partner_email,
'description': _get_desc,
}
def close(self, cr, uid, ids, context=None):
if 'task_id' in context:
self.pool.get('project.task').write(cr, uid, [context['task_id']], {'state': 'done', 'date_end':time.strftime('%Y-%m-%d %H:%M:%S'), 'remaining_hours': 0.0})
return {}
def confirm(self, cr, uid, ids, context=None):
if context is None:
context = {}
if not 'task_id' in context:
return {}
close_task = self.read(cr, uid, ids[0], [])
to_adr = []
description = close_task['description']
if 'task_id' in context:
if context.get('send_manager', False) and not close_task.get('manager_email', False):
raise osv.except_osv(_('Error'), _("Please specify the email address of Project Manager."))
elif context.get('send_partner', False) and not close_task.get('partner_email', False):
raise osv.except_osv(_('Error'), _("Please specify the email address of partner."))
else:
task_obj = self.pool.get('project.task')
task = task_obj.browse(cr, uid, context['task_id'], context=context)
project = task.project_id
subject = "Task '%s' closed" % task.name
if task.user_id and task.user_id.address_id and task.user_id.address_id.email:
from_adr = task.user_id.address_id.email
signature = task.user_id.signature
else:
raise osv.except_osv(_('Error'), _("Couldn't send mail because your email address is not configured!"))
val = {
'name': task.name,
'user_id': task.user_id.name,
'task_id': "%d/%d" % (project.id, task.id),
'date_start': task.date_start,
'date_end': task.date_end,
'state': task.state
}
header = (project.warn_header or '') % val
footer = (project.warn_footer or '') % val
body = u'%s\n%s\n%s\n\n-- \n%s' % (header, description, footer, signature)
to_adr.append(context.get('send_manager', '') and close_task.get('manager_email', '') or '')
to_adr.append(context.get('send_partner', '') and close_task.get('partner_email', '') or '')
mail_id = email(from_adr, to_adr, subject, body.encode('utf-8'), email_bcc=[from_adr])
if not mail_id:
raise osv.except_osv(_('Error'), _("Couldn't send mail! Check the email ids and smtp configuration settings"))
task_obj.write(cr, uid, [task.id], {'state': 'done', 'date_end':time.strftime('%Y-%m-%d %H:%M:%S'), 'remaining_hours': 0.0})
message = _('Task ') + " '" + task.name + "' "+ _("is Done.")
self.log(cr, uid, task.id, message)
return {}
project_close_task()
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

View File

@ -1,43 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<openerp>
<data>
<record id="view_project_close_task" model="ir.ui.view">
<field name="name">Project Close Task</field>
<field name="model">close.task</field>
<field name="type">form</field>
<field name="arch" type="xml">
<form string="Project Close Task" >
<label string="Send mail to the specified email address"/>
<separator string="" colspan="4"/>
<group colspan="4" col="6">
<newline/>
<field name="manager_email" invisible="not context.get('send_manager',False)"/>
<newline/>
<field name="partner_email" invisible="not context.get('send_partner',False)"/>
<newline/>
<field name="description" />
</group>
<separator string="" colspan="6"/>
<group colspan="6" col="6">
<button icon="gtk-ok" name="confirm" string="Send and Close" type="object"/>
<button icon="gtk-ok" string="Close" name="close" type="object"/>
<button icon="gtk-cancel" special="cancel" string="_Cancel"/>
</group>
</form>
</field>
</record>
<record id="action_project_close_task" model="ir.actions.act_window">
<field name="name">Project Close Task</field>
<field name="type">ir.actions.act_window</field>
<field name="res_model">close.task</field>
<field name="view_type">form</field>
<field name="view_mode">form</field>
<field name="view_id" ref="view_project_close_task"/>
<field name="context">{'record_id' : active_id}</field>
<field name="target">new</field>
</record>
</data>
</openerp>

View File

@ -0,0 +1,126 @@
# -*- coding: utf-8 -*-
##############################################################################
#
# OpenERP, Open Source Management Solution
# Copyright (C) 2004-2010 Tiny SPRL (<http://tiny.be>).
#
# 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 <http://www.gnu.org/licenses/>.
#
##############################################################################
import time
from osv import fields, osv
from tools.translate import _
from tools import email_send as email
class project_task_close(osv.osv_memory):
"""
Close Task
"""
_name = "project.task.close"
_description = "Project Close Task"
_columns = {
'manager_warn': fields.boolean("Warn Manager", help="Warn Manager by Email"),
'partner_warn': fields.boolean("Warn Customer", help="Warn Customer by Email"),
'manager_email': fields.char('Manager Email', size=128, help="Email Address of Project's Manager"),
'partner_email': fields.char('Customer Email', size=128, help="Email Address of Customer"),
'description': fields.text('Description'),
}
def default_get(self, cr, uid, fields, context=None):
"""
This function gets default values
"""
if context is None:
context = {}
record_id = context and context.get('active_id', False) or False
task_pool = self.pool.get('project.task')
project_pool = self.pool.get('project.project')
res = super(project_task_close, self).default_get(cr, uid, fields, context=context)
task = task_pool.browse(cr, uid, record_id, context=context)
project = task.project_id
manager = project.user_id or False
partner = task.partner_id or task.project_id.partner_id
if 'description' in fields:
res.update({'description': task.description})
if 'manager_warn' in fields:
res.update({'manager_warn': project.warn_manager})
if 'partner_warn' in fields:
res.update({'partner_warn': project.warn_customer})
if 'manager_email' in fields:
res.update({'manager_email': manager and manager.user_email or False})
if partner and len(partner.address) and 'partner_email' in fields:
res.update({'partner_email': partner.address[0].email})
return res
def done(self, cr, uid, ids, context=None):
task_pool = self.pool.get('project.task')
task_id = context.get('active_id', False)
res = task_pool.do_close(cr, uid, [task_id], context=context)
return res
def confirm(self, cr, uid, ids, context=None):
if context is None:
context = {}
task_pool = self.pool.get('project.task')
task_id = context.get('active_id', False)
if not task_id:
return {}
task = task_pool.browse(cr, uid, task_id, context=context)
for data in self.browse(cr, uid, ids, context=context):
res = task_pool.do_close(cr, uid, [task.id], context=context)
if res:
# Send Warn Message by Email to Manager and Customer
if data.manager_warn and not data.manager_email:
raise osv.except_osv(_('Error'), _("Please specify the email address of Project Manager."))
elif data.partner_warn and not data.partner_email:
raise osv.except_osv(_('Error'), _("Please specify the email address of Customer."))
elif data.manager_warn or data.partner_warn:
project = task.project_id
subject = _("Task '%s' Closed") % task.name
if task.user_id and task.user_id.address_id and task.user_id.address_id.email:
from_adr = task.user_id.address_id.email
signature = task.user_id.signature
else:
raise osv.except_osv(_('Error'), _("Couldn't send mail because your email address is not configured!"))
val = {
'name': task.name,
'user_id': task.user_id.name,
'task_id': "%d/%d" % (project.id, task.id),
'date_start': task.date_start,
'date_end': task.date_end,
'state': task.state
}
header = (project.warn_header or '') % val
footer = (project.warn_footer or '') % val
body = u'%s\n%s\n%s\n\n-- \n%s' % (header, description, footer, signature)
if data.manager_warn and data.manager_email:
to_adr.append(data.manager_email)
if data.partner_warn and data.partner_email:
to_adr.append(data.partner_email)
mail_id = email(from_adr, to_adr, subject, tools.ustr(body), email_bcc=[from_adr])
if not mail_id:
raise osv.except_osv(_('Error'), _("Couldn't send mail! Check the email ids and smtp configuration settings"))
return {}
project_task_close()
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

View File

@ -0,0 +1,43 @@
<?xml version="1.0" encoding="utf-8"?>
<openerp>
<data>
<record id="view_project_task_close" model="ir.ui.view">
<field name="name">Done Task</field>
<field name="model">project.task.close</field>
<field name="type">form</field>
<field name="arch" type="xml">
<form string="Done Task" >
<separator string="Done Task and Inform to Project Manager or Customer by Email " colspan="4"/>
<group colspan="4" col="4">
<field name="manager_warn" invisible="1"/>
<field name="manager_email" widget="email" attrs="{'invisible':[('manager_warn','=',False)], 'required':[('manager_warn','=',True)]}"/>
<field name="partner_warn" invisible="1"/>
<field name="partner_email" widget="email" attrs="{'invisible':[('partner_warn','=',False)], 'required':[('partner_warn','=',True)]}"/>
<separator string="Warn Message" colspan="4"/>
<field name="description" nolabel="1" colspan="4"/>
</group>
<separator string="" colspan="4"/>
<group colspan="2" col="2">
</group>
<group colspan="2" col="3">
<button icon="gtk-close" special="cancel" string="_Close"/>
<button icon="gtk-jump-to" string="_Done" special="cancel" name="done" type="object"/>
<button icon="terp-mail-message-new" string="_Send+Done" name="confirm" type="object"/>
</group>
</form>
</field>
</record>
<record id="action_project_task_close" model="ir.actions.act_window">
<field name="name">Done Task</field>
<field name="type">ir.actions.act_window</field>
<field name="res_model">project.task.close</field>
<field name="view_type">form</field>
<field name="view_mode">form</field>
<field name="view_id" ref="view_project_task_close"/>
<field name="target">new</field>
</record>
</data>
</openerp>

View File

@ -38,67 +38,54 @@ class project_task_delegate(osv.osv_memory):
'state': fields.selection([('pending','Pending'), ('done','Done'), ], 'Validation State', required=True, help="New state of your own task. Pending will be reopened automatically when the delegated task is closed")
}
def _get_name(self, cr, uid, context=None):
def default_get(self, cr, uid, fields, context=None):
"""
This function gets default values
"""
res = super(project_task_delegate, self).default_get(cr, uid, fields, context=context)
if context is None:
context = {}
if 'active_id' in context:
task = self.pool.get('project.task').browse(cr, uid, context['active_id'])
record_id = context and context.get('active_id', False) or False
task_pool = self.pool.get('project.task')
task = task_pool.browse(cr, uid, record_id, context=context)
project = task.project_id
manager = project.user_id or False
partner = task.partner_id or task.project_id.partner_id
if 'name' in fields:
if task.name.startswith(_('CHECK: ')):
newname = str(task.name).replace(_('CHECK: '), '')
else:
newname = task.name or ''
return newname
return ''
def _get_plan_hour(self, cr, uid, context=None):
if context is None:
context = {}
if 'active_id' in context:
task = self.pool.get('project.task').browse(cr, uid, context['active_id'])
return task.remaining_hours
return 0.0
def _get_prefix(self, cr, uid, context=None):
if context is None:
context = {}
if 'active_id' in context:
task = self.pool.get('project.task').browse(cr, uid, context['active_id'])
res.update({'name': newname})
if 'planned_hours' in fields:
res.update({'planned_hours': task.remaining_hours or 0.0})
if 'prefix' in fields:
if task.name.startswith(_('CHECK: ')):
newname = str(task.name).replace(_('CHECK: '), '')
else:
newname = task.name or ''
return _('CHECK: ') + newname
return ''
prefix = _('CHECK: ') + newname
res.update({'prefix': prefix})
if 'new_task_description' in fields:
res.update({'new_task_description': task.description})
return res
def _get_new_desc(self, cr, uid, context=None):
if context is None:
context = {}
if 'active_id' in context:
task = self.pool.get('project.task').browse(cr, uid, context['active_id'])
return task.description
return ''
_defaults = {
'name': _get_name,
'planned_hours': _get_plan_hour,
'planned_hours_me': 1.0,
'prefix': _get_prefix,
'new_task_description': _get_new_desc,
'state': 'pending',
}
def fields_view_get(self, cr, uid, view_id=None, view_type='form', context=None, toolbar=False, submenu=False):
users_obj = self.pool.get('res.users')
obj_tm = users_obj.browse(cr, uid, uid, context).company_id.project_time_mode_id
tm = obj_tm and obj_tm.name or 'Hours'
res = super(project_task_delegate, self).fields_view_get(cr, uid, view_id, view_type, context, toolbar, submenu=submenu)
users_pool = self.pool.get('res.users')
obj_tm = users_pool.browse(cr, uid, uid, context).company_id.project_time_mode_id
tm = obj_tm and obj_tm.name or 'Hours'
if tm in ['Hours','Hour']:
return res
eview = etree.fromstring(res['arch'])
def _check_rec(eview):
if eview.attrib.get('widget','') == 'float_time':
eview.set('widget','float')
@ -107,47 +94,19 @@ class project_task_delegate(osv.osv_memory):
return True
_check_rec(eview)
res['arch'] = etree.tostring(eview)
for f in res['fields']:
if 'Hours' in res['fields'][f]['string']:
res['fields'][f]['string'] = res['fields'][f]['string'].replace('Hours',tm)
for field in res['fields']:
if 'Hours' in res['fields'][field]['string']:
res['fields'][field]['string'] = res['fields'][field]['string'].replace('Hours',tm)
return res
def validate(self, cr, uid, ids, context=None):
def delegate(self, cr, uid, ids, context=None):
if context is None:
context = {}
task_obj = self.pool.get('project.task')
user_obj = self.pool.get('res.users')
task_id = context.get('active_id', False)
task_pool = self.pool.get('project.task')
delegate_data = self.read(cr, uid, ids, context=context)[0]
task = task_obj.browse(cr, uid, context['active_id'], context=context)
newname = delegate_data['prefix'] or ''
new_task_id = task_obj.copy(cr, uid, task.id, {
'name': delegate_data['name'],
'user_id': delegate_data['user_id'],
'planned_hours': delegate_data['planned_hours'],
'remaining_hours': delegate_data['planned_hours'],
'parent_ids': [(6, 0, [task.id])],
'state': 'draft',
'description': delegate_data['new_task_description'] or '',
'child_ids': [],
'work_ids': []
}, context)
task_obj.write(cr, uid, [task.id], {
'remaining_hours': delegate_data['planned_hours_me'],
'planned_hours': delegate_data['planned_hours_me'] + (task.effective_hours or 0.0),
'name': newname,
}, context)
if delegate_data['state'] == 'pending':
task_obj.do_pending(cr, uid, [task.id], context)
else:
context.update({'mail_send': False} )
task_obj.do_close(cr, uid, [task.id], context)
delegrate_user = user_obj.browse(cr, uid, delegate_data['user_id'], context=context)
message = _('Task ') + " '" + delegate_data['name'] + "' "+ _("is Delegated to User:") +" '"+ delegrate_user.name +"' "
self.log(cr, uid, task.id, message)
task_pool.do_delegate(cr, uid, task_id, delegate_data, context=context)
return {}
project_task_delegate()

View File

@ -8,25 +8,25 @@
<field name="type">form</field>
<field name="arch" type="xml">
<form string="Project Task Delegate">
<separator string="Delegated Task" colspan="4"/>
<field name="user_id"/>
<newline/>
<field name="planned_hours" widget="float_time"/>
<newline/>
<field name="name"/>
<newline/>
<field name="new_task_description"/>
<newline/>
<separator string="Validation Task" colspan="4"/>
<field name="planned_hours_me" widget="float_time"/>
<newline/>
<field name="prefix" />
<newline/>
<field name="state" />
<newline/>
<group colspan="4" col="6">
<button icon="gtk-cancel" special="cancel" string="_Cancel"/>
<button icon="gtk-ok" name="validate" string="Approve" type="object"/>
<group colspan="2" col="2">
<separator string="Delegated Task" colspan="4"/>
<field name="user_id" colspan="4"/>
<field name="planned_hours" widget="float_time" colspan="4"/>
<field name="name" colspan="4"/>
<field name="new_task_description" colspan="4" />
</group>
<group colspan="2" col="2">
<separator string="Validation Task" colspan="4"/>
<field name="planned_hours_me" widget="float_time" colspan="4"/>
<field name="prefix" colspan="4"/>
<field name="state" colspan="4"/>
</group>
<separator string="" colspan="4"/>
<group colspan="2" col="2">
</group>
<group colspan="2" col="2">
<button icon="gtk-close" special="cancel" string="_Close"/>
<button icon="gtk-ok" name="delegate" string="_Delegate" type="object"/>
</group>
</form>
</field>

View File

@ -0,0 +1,83 @@
# -*- coding: utf-8 -*-
##############################################################################
#
# OpenERP, Open Source Management Solution
# Copyright (C) 2004-2010 Tiny SPRL (<http://tiny.be>).
#
# 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 <http://www.gnu.org/licenses/>.
#
##############################################################################
from lxml import etree
from osv import fields, osv
from tools.translate import _
class project_task_reevaluate(osv.osv_memory):
_name = 'project.task.reevaluate'
def _get_remaining(self,cr, uid, context=None):
if context is None:
context = {}
active_id = context.get('active_id', False)
res = False
if active_id:
res = self.pool.get('project.task').browse(cr, uid, active_id, context=context).remaining_hours
return res
_columns = {
'remaining_hours' : fields.float('Remaining Hours', digits=(16,2), help="Put here the remaining hours required to close the task."),
}
_defaults = {
'remaining_hours': _get_remaining,
}
def fields_view_get(self, cr, uid, view_id=None, view_type='form', context=None, toolbar=False, submenu=False):
res = super(project_task_reevaluate, self).fields_view_get(cr, uid, view_id, view_type, context, toolbar, submenu=submenu)
users_pool = self.pool.get('res.users')
time_mode = users_pool.browse(cr, uid, uid, context).company_id.project_time_mode_id
time_mode_name = time_mode and time_mode.name or 'Hours'
if time_mode_name in ['Hours','Hour']:
return res
eview = etree.fromstring(res['arch'])
def _check_rec(eview):
if eview.attrib.get('widget','') == 'float_time':
eview.set('widget','float')
for child in eview:
_check_rec(child)
return True
_check_rec(eview)
res['arch'] = etree.tostring(eview)
for field in res['fields']:
if 'Hours' in res['fields'][field]['string']:
res['fields'][field]['string'] = res['fields'][field]['string'].replace('Hours',time_mode_name)
return res
def compute_hours(self, cr, uid, ids, context=None):
if context is None:
context = {}
data = self.browse(cr, uid, ids, context=context)[0]
task_pool = self.pool.get('project.task')
task_id = context.get('active_id', False)
if task_id:
task_pool.write(cr, uid, task_id, {'remaining_hours': data.remaining_hours})
if context.get('button_reactivate', False):
task_pool.do_reopen(cr, uid, [task_id], context=context)
return {}
project_task_reevaluate()

View File

@ -0,0 +1,33 @@
<?xml version="1.0" encoding="utf-8"?>
<openerp>
<data>
<record id="view_project_task_reevaluate" model="ir.ui.view">
<field name="name">Re-evaluate Task</field>
<field name="model">project.task.reevaluate</field>
<field name="type">form</field>
<field name="arch" type="xml">
<form string="Reevaluate Task">
<separator colspan="4" string="Reevaluation Task"/>
<field name="remaining_hours" widget="float_time"/>
<separator string="" colspan="4"/>
<group col="2" colspan="2">
</group>
<group col="2" colspan="2">
<button icon="gtk-close" special="cancel" string="_Close"/>
<button icon="gtk-apply" name="compute_hours" string="_Evaluate" type="object" default_focus="1"/>
</group>
</form>
</field>
</record>
<record id="action_project_task_reevaluate" model="ir.actions.act_window">
<field name="name">Re-evaluate Task</field>
<field name="type">ir.actions.act_window</field>
<field name="res_model">project.task.reevaluate</field>
<field name="view_type">form</field>
<field name="view_mode">form</field>
<field name="target">new</field>
</record>
</data>
</openerp>

View File

@ -86,6 +86,7 @@
<field name="view_id" ref="board_project_issue_form"/>
</record>
<menuitem id="menu_deshboard_project_issue" name="Project Issue Dashboard" parent="project.next_id_86"
icon="terp-graph"
action="open_board_project_issue"/>
</data>
</openerp>

View File

@ -63,10 +63,10 @@
<separator colspan="4"/>
<group col="8" colspan="4">
<field name="state" />
<button name="case_close" string="Done" states="open,draft,pending" type="object" icon="gtk-jump-to"/>
<button name="case_open" string="Open" states="draft,pending" type="object" icon="gtk-go-forward"/>
<button name="case_cancel" string="Cancel" states="draft,open,pending" type="object" icon="gtk-cancel"/>
<button name="case_close" string="Close" states="open,draft,pending" type="object" icon="gtk-jump-to"/>
<button name="case_pending" string="Pending" states="draft,open" type="object" icon="gtk-media-pause"/>
<button name="case_cancel" string="Cancel" states="draft,open,pending" type="object" icon="gtk-cancel"/>
<button name="case_escalate" string="Escalate" states="open,draft,pending" type="object" icon="gtk-go-up"/>
<button name="case_reset" string="Reset to Draft" states="done,cancel" type="object" icon="gtk-convert"/>
</group>

View File

@ -27,14 +27,14 @@
"category": "Generic Modules/Projects & Services",
"depends": ["resource", "project"],
"description": """
Long Term Project management module that tracks planning, scheduling, resources allocation.
Mainly used with Big project management.
- Project Phases will be maintained by Manager of the project
- Compute Phase Scheduling: Compute start date and end date of the phases which are in draft,open and pending state of the project given.
If no project given then all the draft,open and pending state phases will be taken
- Compute Task Scheduling: This works same as the scheduler button on project.phase. It takes the project as argument and computes all the open,draft and pending tasks
- Schedule Tasks: All the tasks which are in draft,pending and open state are scheduled with taking the phase's start date
Long Term Project management module that tracks planning, scheduling, resources allocation.
Features.
- Manage Big project.
- Define various Phases of Project.
- Compute Phase Scheduling: Compute start date and end date of the phases which are in draft,open and pending state of the project given.
If no project given then all the draft,open and pending state phases will be taken
- Compute Task Scheduling: This works same as the scheduler button on project.phase. It takes the project as argument and computes all the open,draft and pending tasks
- Schedule Tasks: All the tasks which are in draft,pending and open state are scheduled with taking the phase's start date
""",
"init_xml": [],

View File

@ -72,9 +72,9 @@
<field name="name">Resource Allocations</field>
<field name="res_model">project.resource.allocation</field>
<field name="view_type">form</field>
<field name="view_mode">gantt,tree,form</field>
<field name="view_mode">tree,form,gantt</field>
<field name="context">{}</field>
<!--<field name="search_view_id" ref="view_project_phase_search"/>-->
<field name="search_view_id" ref="view_project_resource_allocation_search"/>
</record>
@ -254,7 +254,7 @@
<field name="name">Project Phases</field>
<field name="res_model">project.phase</field>
<field name="view_type">form</field>
<field name="view_mode">gantt,tree,form,calendar</field>
<field name="view_mode">tree,form,gantt,calendar</field>
<field name="context">{'search_default_responsible_id':uid}</field>
<field name="search_view_id" ref="view_project_phase_search"/>
<field name="help">You can subdivide your larger projects into several phases. For each phase, you can define your resources allocation (humans or engine), describe de differend task and link your phase with previous and next one, add constraints date and scheduling. A gantt view of your project phase is also available from this menu. Gantt view is a graphically draw of the project plan; it includes any task dependencies by visually adjusting task durations and priorities, and by linking tasks to each other.</field>
@ -314,13 +314,13 @@
<menuitem action="act_project_phase"
groups="base.group_extended"
id="menu_project_phase" parent="base.menu_project_long_term" sequence="1"/>
id="menu_project_phase" parent="base.menu_project_long_term" sequence="1"/>
<menuitem id="menu_resouce_allocation" action="act_resouce_allocation"
name="Resource Allocations" parent="base.menu_project_long_term" sequence="2"/>
<menuitem id="menu_pm_resources_project1"
groups="base.group_extended"
groups="base.group_extended"
name="Resources" parent="project.menu_definitions" sequence="3"/>
<menuitem id="menu_phase_schedule" name="Scheduling" parent="base.menu_project_long_term" sequence="4" groups="project.group_project_user,project.group_project_manager,base.group_system"/>

View File

@ -8,20 +8,16 @@
<field name="type">form</field>
<field name="arch" type="xml">
<form string="Compute Scheduling of Phases">
<group width="380" height="180">
<group colspan="4" col="4">
<label colspan="4" string="This wizard will schedule phases for all or specified project" />
<newline />
<field name="target_project" colspan="4"/>
</group>
<newline />
<group colspan="4" col="6" attrs="{'invisible':[('target_project','=','all')]}">
<field name="project_id"/>
</group>
<group colspan="4" col="4">
<separator colspan="4" string="Compute Scheduling of phases for all or specified project" />
<field name="target_project" colspan="4"/>
<field name="project_id" widget="selection" colspan="4" attrs="{'invisible':[('target_project','=','all')], 'required':[('target_project','!=','all')]}"/>
<separator colspan="4"/>
<group colspan="4" col="6"> <!-- Improve me -->
<button icon="gtk-cancel" special="cancel" string="_Cancel"/>
<button icon="gtk-ok" name="check_selection" string="_Compute" type="object"/>
<group colspan="2" col="2">
</group>
<group colspan="2" col="2"> <!-- Improve me -->
<button icon="gtk-close" special="cancel" string="_Close"/>
<button icon="gtk-ok" name="check_selection" string="C_ompute" type="object"/>
</group>
</group>
</form>

View File

@ -7,12 +7,16 @@
<field name="model">project.compute.tasks</field>
<field name="type">form</field>
<field name="arch" type="xml">
<form string="Compute Scheduling of Phases">
<group colspan="4" height="100" width="500">
<field name="project_id"/>
<group colspan="4" col="6">
<button icon="gtk-cancel" special="cancel" string="_Cancel"/>
<button icon="gtk-ok" name="compute_date" string="Compute" type="object"/>
<form string="Compute Scheduling of Task">
<group colspan="4">
<separator colspan="4" string="Compute Scheduling of Task for specified project." />
<field name="project_id" widget="selection" colspan="4"/>
<separator colspan="4"/>
<group colspan="2" col="2">
</group>
<group colspan="2" col="2">
<button icon="gtk-close" special="cancel" string="_Close"/>
<button icon="gtk-ok" name="compute_date" string="C_ompute" type="object"/>
</group>
</group>
</form>

View File

@ -55,9 +55,7 @@ class project_with_message(osv.osv):
_inherit = 'project.project'
_columns = {
'message_ids':fields.one2many(
'project.messages', 'project_id', 'Messages',
),
'message_ids':fields.one2many('project.messages', 'project_id', 'Messages'),
}
project_with_message()

View File

@ -90,8 +90,20 @@
<field name="search_view_id" ref="view_project_messages_search"/>
<field name="context">{"search_default_to_id":uid}</field>
<field name="view_id" ref="view_project_message_tree"/>
<field name="help">An in-project messagery system permits an efficient and trackable communication between project members. The messages are kept in the system and can then be used for post-analysis.</field>
</record>
<act_window domain="[('project_id', '=', active_id)]" id="act_project_messages" name="Messages" res_model="project.messages" src_model="project.project"/>
<!--Actions for deshboard -->
<record id="action_view_project_editable_messages_tree" model="ir.actions.act_window">
<field name="name">Messages</field>
<field name="res_model">project.messages</field>
<field name="view_type">form</field>
<field name="view_mode">tree,form</field>
<field name="view_id" ref="project_messages.view_project_message_tree"/>
</record>
<menuitem action="messages_form" id="menu_messages_form" parent="project.menu_project_management"/>
</data>
</openerp>

View File

@ -58,6 +58,7 @@
<menuitem
id="menu_deshboard_scurm"
name="Scrum Dashboard" parent="project.next_id_86"
icon="terp-graph"
action="open_board_project_scrum"/>
</data>
</openerp>

View File

@ -45,49 +45,29 @@ class project_scrum_sprint(osv.osv):
_name = 'project.scrum.sprint'
_description = 'Project Scrum Sprint'
def _calc_progress(self, cr, uid, ids, name, args, context=None):
res = {}
def _compute(self, cr, uid, ids, fields, arg, context=None):
res = {}.fromkeys(ids, 0.0)
progress = {}
if not ids:
return res
if context is None:
context = {}
for sprint in self.browse(cr, uid, ids):
for sprint in self.browse(cr, uid, ids, context=context):
tot = 0.0
prog = 0.0
effective = 0.0
progress = 0.0
for bl in sprint.backlog_ids:
tot += bl.expected_hours
effective += bl.effective_hours
prog += bl.expected_hours * bl.progress / 100.0
res.setdefault(sprint.id, 0.0)
if tot>0:
res[sprint.id] = round(prog/tot*100)
return res
def _calc_effective(self, cr, uid, ids, name, args, context=None):
res = {}
if context is None:
context = {}
for sprint in self.browse(cr, uid, ids):
res.setdefault(sprint.id, 0.0)
for bl in sprint.backlog_ids:
res[sprint.id] += bl.effective_hours
return res
def _calc_planned(self, cr, uid, ids, name, args, context=None):
res = {}
if context is None:
context = {}
for sprint in self.browse(cr, uid, ids):
res.setdefault(sprint.id, 0.0)
for bl in sprint.backlog_ids:
res[sprint.id] += bl.expected_hours
return res
def _calc_expected(self, cr, uid, ids, name, args, context=None):
res = {}
if context is None:
context = {}
for sprint in self.browse(cr, uid, ids):
res.setdefault(sprint.id, 0.0)
for bl in sprint.backlog_ids:
res[sprint.id] += bl.expected_hours
progress = round(prog/tot*100)
res[sprint.id] = {
'progress' : progress,
'expected_hours' : tot,
'effective_hours': effective,
}
return res
def button_cancel(self, cr, uid, ids, context=None):
@ -137,9 +117,9 @@ class project_scrum_sprint(osv.osv):
'review': fields.text('Sprint Review'),
'retrospective': fields.text('Sprint Retrospective'),
'backlog_ids': fields.one2many('project.scrum.product.backlog', 'sprint_id', 'Sprint Backlog'),
'progress': fields.function(_calc_progress, method=True, string='Progress (0-100)', help="Computed as: Time Spent / Total Time."),
'effective_hours': fields.function(_calc_effective, method=True, string='Effective hours', help="Computed using the sum of the task work done."),
'expected_hours': fields.function(_calc_expected, method=True, string='Planned Hours', help='Estimated time to do the task.'),
'progress': fields.function(_compute, group_operator="avg", type='float', multi="progress", method=True, string='Progress (0-100)', help="Computed as: Time Spent / Total Time."),
'effective_hours': fields.function(_compute, multi="effective_hours", method=True, string='Effective hours', help="Computed using the sum of the task work done."),
'expected_hours': fields.function(_compute, multi="expected_hours", method=True, string='Planned Hours', help='Estimated time to do the task.'),
'state': fields.selection([('draft','Draft'),('open','Open'),('pending','Pending'),('cancel','Cancelled'),('done','Done')], 'State', required=True),
}
_defaults = {
@ -188,39 +168,31 @@ class project_scrum_product_backlog(osv.osv):
return self.name_get(cr, uid, ids, context=context)
return super(project_scrum_product_backlog, self).name_search(cr, uid, name, args, operator,context, limit=limit)
def _calc_progress(self, cr, uid, ids, name, args, context=None):
res = {}
def _compute(self, cr, uid, ids, fields, arg, context=None):
res = {}.fromkeys(ids, 0.0)
progress = {}
if not ids:
return res
if context is None:
context = {}
for bl in self.browse(cr, uid, ids):
for backlog in self.browse(cr, uid, ids, context=context):
tot = 0.0
prog = 0.0
for task in bl.tasks_id:
effective = 0.0
task_hours = 0.0
progress = 0.0
for task in backlog.tasks_id:
task_hours += task.total_hours
effective += task.effective_hours
tot += task.planned_hours
prog += task.planned_hours * task.progress / 100.0
res.setdefault(bl.id, 0.0)
if tot>0:
res[bl.id] = round(prog/tot*100)
return res
def _calc_effective(self, cr, uid, ids, name, args, context=None):
res = {}
if context is None:
context = {}
for bl in self.browse(cr, uid, ids):
res.setdefault(bl.id, 0.0)
for task in bl.tasks_id:
res[bl.id] += task.effective_hours
return res
def _calc_task(self, cr, uid, ids, name, args, context=None):
res = {}
if context is None:
context = {}
for bl in self.browse(cr, uid, ids):
res.setdefault(bl.id, 0.0)
for task in bl.tasks_id:
res[bl.id] += task.total_hours
progress = round(prog/tot*100)
res[backlog.id] = {
'progress' : progress,
'effective_hours': effective,
'task_hours' : task_hours
}
return res
def button_cancel(self, cr, uid, ids, context=None):
@ -291,11 +263,11 @@ class project_scrum_product_backlog(osv.osv):
'sequence' : fields.integer('Sequence', help="Gives the sequence order when displaying a list of product backlog."),
'tasks_id': fields.one2many('project.task', 'product_backlog_id', 'Tasks Details'),
'state': fields.selection([('draft','Draft'),('open','Open'),('pending','Pending'),('done','Done'),('cancel','Cancelled')], 'State', required=True),
'progress': fields.function(_calc_progress, method=True, string='Progress', help="Computed as: Time Spent / Total Time."),
'effective_hours': fields.function(_calc_effective, method=True, string='Spent Hours', help="Computed using the sum of the time spent on every related tasks"),
'progress': fields.function(_compute, multi="progress", group_operator="avg", type='float', method=True, string='Progress', help="Computed as: Time Spent / Total Time."),
'effective_hours': fields.function(_compute, multi="effective_hours", method=True, string='Spent Hours', help="Computed using the sum of the time spent on every related tasks"),
'expected_hours': fields.float('Planned Hours', help='Estimated total time to do the Backlog'),
'create_date': fields.datetime("Creation Date", readonly=True),
'task_hours': fields.function(_calc_task, method=True, string='Task Hours', help='Estimated time of the total hours of the tasks')
'task_hours': fields.function(_compute, multi="task_hours", method=True, string='Task Hours', help='Estimated time of the total hours of the tasks')
}
_defaults = {
'state': 'draft',

View File

@ -24,7 +24,7 @@ class backlog_create_task(osv.osv_memory):
_name = 'project.scrum.backlog.create.task'
_description = 'Create Tasks from Product Backlogs'
_columns = {
'user_id': fields.many2one('res.users', 'Assign To')
'user_id': fields.many2one('res.users', 'Assign To', help="Resposible user who can work on task")
}
def do_create(self, cr, uid, ids, context=None):

View File

@ -7,21 +7,22 @@
<field name="model">project.scrum.backlog.create.task</field>
<field name="type">form</field>
<field name="arch" type="xml">
<form string="Create Tasks">
<group col="4" colspan="6">
<field name="user_id"/>
</group>
<form string="Convert into Tasks">
<separator string="Convert into Tasks" colspan="4"/>
<field name="user_id"/>
<separator colspan="4"/>
<group col="2" colspan="4">
<button special="cancel" string="Cancel" icon='gtk-cancel'/>
<button name="do_create" string="Create Tasks" colspan="1" type="object" icon="gtk-execute"/>
<group col="2" colspan="2">
</group>
<group col="2" colspan="2">
<button special="cancel" string="_Close" icon='gtk-close'/>
<button name="do_create" string="Co_nvert" colspan="1" type="object" icon="gtk-execute"/>
</group>
</form>
</field>
</record>
<record id="action_scrum_backlog_to_task" model="ir.actions.act_window">
<field name="name">Create Tasks</field>
<field name="name">Convert into Tasks</field>
<field name="type">ir.actions.act_window</field>
<field name="res_model">project.scrum.backlog.create.task</field>
<field name="view_type">form</field>
@ -32,7 +33,7 @@
<record model="ir.values" id="scrum_backlog_to_task_values">
<field name="model_id" ref="model_project_scrum_product_backlog" />
<field name="object" eval="1" />
<field name="name">Create Tasks</field>
<field name="name">Convert into Tasks</field>
<field name="key2">client_action_multi</field>
<field name="value" eval="'ir.actions.act_window,' + str(ref('action_scrum_backlog_to_task'))" />
<field name="key">action</field>

View File

@ -10,7 +10,7 @@
<separator string="Are you sure you want to merge these Backlogs?" colspan="4"/>
<label colspan="4" string="This wizard merge backlogs and create one new backlog with draft state (Old backlogs Will be deleted). And it also merge old tasks from backlogs" />
<separator colspan="4"/>
<button colspan="2" special="cancel" string="Cancel" icon="gtk-cancel"/>
<button colspan="2" special="cancel" string="Close" icon="gtk-close"/>
<button colspan="2" default_focus="1" name="check_backlogs" string="Merge" type="object" icon="gtk-execute"/>
</form>
</field>

View File

@ -25,8 +25,8 @@ class backlog_sprint_assign(osv.osv_memory):
_name = 'project.scrum.backlog.assign.sprint'
_description = 'Assign sprint to backlogs'
_columns = {
'sprint_id': fields.many2one('project.scrum.sprint', 'Sprint Name', required=True),
'state_open': fields.boolean('Set Open', help="Change the state of product backlogs to open if its in draft state"),
'sprint_id': fields.many2one('project.scrum.sprint', 'Sprint', required=True, help="Select Sprint to assign backlog."),
'state_open': fields.boolean('Open Backlog', help="Change the state of product backlogs to open if its in draft state"),
'convert_to_task': fields.boolean('Convert To Task', help="Create Task for Product Backlog")
}
_defaults = {

View File

@ -8,20 +8,16 @@
<field name="type">form</field>
<field name="arch" type="xml">
<form string="Assign Sprint">
<group col="4" colspan="6">
<field name="sprint_id" colspan="2"/>
</group>
<newline/>
<separator colspan="2"/>
<newline/>
<group>
<field name="state_open" colspan="1"/>
<field name="convert_to_task" colspan="1"/>
</group>
<separator string="Assign Sprint" colspan="4"/>
<field name="sprint_id" colspan="4"/>
<field name="state_open" />
<field name="convert_to_task"/>
<separator colspan="4"/>
<group col="2" colspan="4">
<button special="cancel" string="Cancel" icon='gtk-cancel'/>
<button name="assign_sprint" string="Assign Sprint" colspan="1" type="object" icon="gtk-execute"/>
<group col="2" colspan="2">
</group>
<group col="2" colspan="2">
<button special="cancel" string="_Close" icon='gtk-close'/>
<button name="assign_sprint" string="_Assign" colspan="1" type="object" icon="gtk-execute"/>
</group>
</form>
</field>
@ -47,4 +43,4 @@
</record>
</data>
</openerp>
</openerp>

View File

@ -20,5 +20,6 @@
import purchase_requisition
import wizard
import report
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

View File

@ -32,7 +32,9 @@
"init_xml" : [],
"demo_xml" : [],
"update_xml" : ["wizard/purchase_requisition_partner_view.xml",
"purchase_requisition_data.xml",
"purchase_requisition_view.xml",
"purchase_requisition_report.xml",
"security/ir.model.access.csv","purchase_requisition_sequence.xml"
],
"active": False,

View File

@ -40,6 +40,7 @@ class purchase_requisition(osv.osv):
'company_id': fields.many2one('res.company', 'Company', required=True),
'purchase_ids' : fields.one2many('purchase.order','requisition_id','Purchase Orders',states={'done': [('readonly', True)]}),
'line_ids' : fields.one2many('purchase.requisition.line','requisition_id','Products to Purchase',states={'done': [('readonly', True)]}),
'warehouse_id': fields.many2one('stock.warehouse', 'Warehouse'),
'state': fields.selection([('draft','Draft'),('in_progress','In Progress'),('cancel','Cancelled'),('done','Done')], 'State', required=True)
}
_defaults = {
@ -51,6 +52,15 @@ class purchase_requisition(osv.osv):
'name': lambda obj, cr, uid, context: obj.pool.get('ir.sequence').get(cr, uid, 'purchase.order.requisition'),
}
def copy(self, cr, uid, id, default=None,context={}):
if not default:
default = {}
default.update({
'state':'draft',
'purchase_ids':[],
'name': self.pool.get('ir.sequence').get(cr, uid, 'purchase.order.requisition'),
})
return super(purchase_requisition, self).copy(cr, uid, id, default, context)
def tender_cancel(self, cr, uid, ids, context=None):
purchase_order_obj = self.pool.get('purchase.order')
for purchase in self.browse(cr, uid, ids):
@ -64,9 +74,6 @@ class purchase_requisition(osv.osv):
return True
def tender_in_progress(self, cr, uid, ids, context=None):
for quotations in self.browse(cr, uid, ids):
if not quotations.purchase_ids:
raise osv.except_osv(_('Purchase order required'),('You should have atleast one purchase order line defined for this tender'))
self.write(cr, uid, ids, {'state':'in_progress'} ,context=context)
for (id,name) in self.name_get(cr, uid, ids):
message = _('Tender') + " '" + name + "' "+ _(" is In Progress")
@ -172,6 +179,8 @@ class procurement_order(osv.osv):
'name': sequence_obj.get(cr, uid, 'purchase.order.requisition'),
'origin': procurement.name,
'date_end': procurement.date_planned,
'warehouse_id':procurement.purchase_id and procurement.purchase_id.warehouse_id.id,
'company_id':procurement.company_id.id,
'line_ids': [(0,0,{
'product_id': procurement.product_id.id,
'product_uom_id': procurement.product_uom.id,

View File

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<openerp>
<data noupdate="1">
<function
eval="('default',False,'warehouse_id', [('purchase.requisition', False)], ref('stock.warehouse0'), True, False, False, False, True)"
id="purchase_default_set"
model="ir.values"
name="set"/>
</data>
</openerp>

View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<openerp>
<data>
<report auto="False" id="report_purchase_requisition" model="purchase.requisition" name="purchase.requisition" rml="purchase_requisition/report/purchase_requisition.rml" string="Purchase Requisition"/>
</data>
</openerp>

View File

@ -2,17 +2,6 @@
<openerp>
<data>
<record model="ir.ui.view" id="purchase_order_tree_inherit">
<field name="name">purchase.order.tree.inherit</field>
<field name="type">tree</field>
<field name="model">purchase.order</field>
<field name="inherit_id" ref="purchase.purchase_order_tree"/>
<field name="arch" type="xml">
<field name="name" position="after">
<field name="requisition_id" groups="base.group_extended"/>
</field>
</field>
</record>
<record model="ir.ui.view" id="purchase_order_form_inherit">
<field name="name">purchase.order.form.inherit</field>
@ -20,12 +9,23 @@
<field name="model">purchase.order</field>
<field name="inherit_id" ref="purchase.purchase_order_form"/>
<field name="arch" type="xml">
<field name="partner_ref" position="after">
<field name="shipped" position="after">
<field name="requisition_id" groups="base.group_extended"/>
</field>
</field>
</record>
<record model="ir.ui.view" id="purchase_order_search_inherit">
<field name="name">purchase.order.list.select.inherit</field>
<field name="type">form</field>
<field name="model">purchase.order</field>
<field name="inherit_id" ref="purchase.view_purchase_order_filter"/>
<field name="arch" type="xml">
<xpath expr="/search/group/filter[@string='To Invoice']" position="after">
<filter icon="terp-gtk-jump-to-rtl" string="Requisition" domain="[('requisition_id','!=',False)]" separator="1"/>
</xpath>
</field>
</record>
<record model="ir.ui.view" id="view_purchase_requisition_form">
<field name="name">purchase.requisition.form</field>
<field name="type">form</field>
@ -39,6 +39,7 @@
<field name="date_start"/>
<field name="date_end"/>
<field name="origin"/>
<field name="warehouse_id" groups="base.group_extended" widget="selection"/>
<field name="company_id" groups="base.group_multi_company" widget="selection"/>
</group>
<notebook colspan="4">
@ -77,12 +78,15 @@
<field name="minimum_planned_date"/>
<field name="origin"/>
<field name="state"/>
<button name="purchase_confirm" states="draft" string="Confirm Purchase Order" icon="gtk-apply"/>
<button name="purchase_approve" states="confirmed" string="Approved by Supplier" icon="gtk-ok"/>
<button name="purchase_cancel" states="draft,confirmed,wait_auth" string="Cancel Purchase Order" icon="gtk-cancel"/>
</tree>
</field>
<separator colspan="4" string=""/>
<group col="8" colspan="4">
<label colspan="6" string=""/>
<button name="%(action_purchase_requisition_partner)d" string="Requests for Quotation" type="action" icon="gtk-execute"
<button name="%(action_purchase_requisition_partner)d" string="Request a Quotation" type="action" icon="gtk-execute"
attrs="{'readonly': [('state', '=', 'done')]}" />
</group>
</page>
@ -123,6 +127,7 @@
<separator orientation="vertical"/>
<field name="name"/>
<field name="user_id" />
<filter icon="terp-personal-" string="Unassigned" domain="[('user_id','=', False)]" help="Unassigned Requisition"/>
<field name="exclusive" />
</group>
<newline/>
@ -181,5 +186,12 @@
</xpath>
</field>
</record>
<act_window
domain="[('requisition_id', '=', active_id)]"
id="act_res_partner_2_purchase_order"
name="Purchase orders"
res_model="purchase.order"
src_model="purchase.requisition"/>
</data>
</openerp>

View File

@ -0,0 +1,24 @@
# -*- coding: utf-8 -*-
##############################################################################
#
# OpenERP, Open Source Management Solution
# Copyright (C) 2004-2010 Tiny SPRL (<http://tiny.be>).
#
# 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 <http://www.gnu.org/licenses/>.
#
##############################################################################
import requisition
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

View File

@ -0,0 +1,226 @@
<?xml version="1.0"?>
<document filename="test.pdf">
<template pageSize="(595.0,842.0)" title="Test" author="Martin Simon" allowSplitting="20">
<pageTemplate id="first">
<frame id="first" x1="34.0" y1="28.0" width="530" height="786"/>
</pageTemplate>
</template>
<stylesheet>
<blockTableStyle id="Standard_Outline">
<blockAlignment value="LEFT"/>
<blockValign value="TOP"/>
</blockTableStyle>
<blockTableStyle id="Table1">
<blockAlignment value="LEFT"/>
<blockValign value="TOP"/>
<lineStyle kind="LINEBELOW" colorName="#e6e6e6" start="0,0" stop="-1,0"/>
<lineStyle kind="LINEBEFORE" colorName="#e6e6e6" start="0,0" stop="0,-1"/>
<lineStyle kind="LINEABOVE" colorName="#e6e6e6" start="0,0" stop="0,0"/>
<lineStyle kind="LINEBELOW" colorName="#e6e6e6" start="0,-1" stop="0,-1"/>
<lineStyle kind="LINEBEFORE" colorName="#e6e6e6" start="1,0" stop="1,-1"/>
<lineStyle kind="LINEABOVE" colorName="#e6e6e6" start="1,0" stop="1,0"/>
<lineStyle kind="LINEBELOW" colorName="#e6e6e6" start="1,-1" stop="1,-1"/>
<lineStyle kind="LINEBEFORE" colorName="#e6e6e6" start="2,0" stop="2,-1"/>
<lineStyle kind="LINEABOVE" colorName="#e6e6e6" start="2,0" stop="2,0"/>
<lineStyle kind="LINEBELOW" colorName="#e6e6e6" start="2,-1" stop="2,-1"/>
<lineStyle kind="LINEBEFORE" colorName="#e6e6e6" start="3,0" stop="3,-1"/>
<lineStyle kind="LINEAFTER" colorName="#e6e6e6" start="3,0" stop="3,-1"/>
<lineStyle kind="LINEABOVE" colorName="#e6e6e6" start="3,0" stop="3,0"/>
<lineStyle kind="LINEBELOW" colorName="#e6e6e6" start="3,-1" stop="3,-1"/>
<lineStyle kind="LINEABOVE" colorName="#cccccc" start="0,2" stop="-1,-1"/>
</blockTableStyle>
<blockTableStyle id="Table2">
<blockAlignment value="LEFT"/>
<blockValign value="TOP"/>
<lineStyle kind="LINEBELOW" colorName="#e6e6e6" start="0,0" stop="-1,0"/>
<lineStyle kind="LINEBEFORE" colorName="#e6e6e6" start="0,0" stop="0,-1"/>
<lineStyle kind="LINEABOVE" colorName="#e6e6e6" start="0,0" stop="0,0"/>
<lineStyle kind="LINEBELOW" colorName="#e6e6e6" start="0,-1" stop="0,-1"/>
<lineStyle kind="LINEBEFORE" colorName="#e6e6e6" start="1,0" stop="1,-1"/>
<lineStyle kind="LINEABOVE" colorName="#e6e6e6" start="1,0" stop="1,0"/>
<lineStyle kind="LINEBELOW" colorName="#e6e6e6" start="1,-1" stop="1,-1"/>
<lineStyle kind="LINEBEFORE" colorName="#e6e6e6" start="2,0" stop="2,-1"/>
<lineStyle kind="LINEABOVE" colorName="#e6e6e6" start="2,0" stop="2,0"/>
<lineStyle kind="LINEBELOW" colorName="#e6e6e6" start="2,-1" stop="2,-1"/>
<lineStyle kind="LINEBEFORE" colorName="#e6e6e6" start="3,0" stop="3,-1"/>
<lineStyle kind="LINEAFTER" colorName="#e6e6e6" start="3,0" stop="3,-1"/>
<lineStyle kind="LINEABOVE" colorName="#e6e6e6" start="3,0" stop="3,0"/>
<lineStyle kind="LINEBELOW" colorName="#e6e6e6" start="3,-1" stop="3,-1"/>
<lineStyle kind="LINEABOVE" colorName="#cccccc" start="0,2" stop="-1,-1"/>
</blockTableStyle>
<blockTableStyle id="Table3">
<blockAlignment value="LEFT"/>
<blockValign value="TOP"/>
<lineStyle kind="LINEBELOW" colorName="#e6e6e6" start="0,0" stop="-1,0"/>
<lineStyle kind="LINEBEFORE" colorName="#e6e6e6" start="0,0" stop="0,-1"/>
<lineStyle kind="LINEABOVE" colorName="#e6e6e6" start="0,0" stop="0,0"/>
<lineStyle kind="LINEBELOW" colorName="#e6e6e6" start="0,-1" stop="0,-1"/>
<lineStyle kind="LINEBEFORE" colorName="#e6e6e6" start="1,0" stop="1,-1"/>
<lineStyle kind="LINEABOVE" colorName="#e6e6e6" start="1,0" stop="1,0"/>
<lineStyle kind="LINEBELOW" colorName="#e6e6e6" start="1,-1" stop="1,-1"/>
<lineStyle kind="LINEBEFORE" colorName="#e6e6e6" start="2,0" stop="2,-1"/>
<lineStyle kind="LINEABOVE" colorName="#e6e6e6" start="2,0" stop="2,0"/>
<lineStyle kind="LINEBELOW" colorName="#e6e6e6" start="2,-1" stop="2,-1"/>
<lineStyle kind="LINEBEFORE" colorName="#e6e6e6" start="3,0" stop="3,-1"/>
<lineStyle kind="LINEAFTER" colorName="#e6e6e6" start="3,0" stop="3,-1"/>
<lineStyle kind="LINEABOVE" colorName="#e6e6e6" start="3,0" stop="3,0"/>
<lineStyle kind="LINEBELOW" colorName="#e6e6e6" start="3,-1" stop="3,-1"/>
<lineStyle kind="LINEABOVE" colorName="#cccccc" start="0,2" stop="-1,-1"/>
</blockTableStyle>
<initialize>
<paraStyle name="all" alignment="justify"/>
</initialize>
<paraStyle name="P1" fontName="Helvetica" fontSize="12.0" leading="15" alignment="LEFT" spaceBefore="0.0" spaceAfter="6.0"/>
<paraStyle name="P2" fontName="Helvetica" fontSize="8.0" leading="10" alignment="LEFT" spaceBefore="0.0" spaceAfter="6.0"/>
<paraStyle name="P3" fontName="Helvetica-Bold" fontSize="12.0" leading="15" alignment="LEFT" spaceBefore="0.0" spaceAfter="6.0"/>
<paraStyle name="P4" fontName="Helvetica-Bold" fontSize="10.0" leading="13" alignment="LEFT" spaceBefore="0.0" spaceAfter="6.0" textColor="#008000"/>
<paraStyle name="Standard" fontName="Helvetica"/>
<paraStyle name="Text body" fontName="Helvetica" spaceBefore="0.0" spaceAfter="6.0"/>
<paraStyle name="List" fontName="Helvetica" spaceBefore="0.0" spaceAfter="6.0"/>
<paraStyle name="Table Contents" fontName="Helvetica" spaceBefore="0.0" spaceAfter="6.0"/>
<paraStyle name="Table Heading" fontName="Helvetica" alignment="CENTER" spaceBefore="0.0" spaceAfter="6.0"/>
<paraStyle name="Caption" fontName="Helvetica" fontSize="10.0" leading="13" spaceBefore="6.0" spaceAfter="6.0"/>
<paraStyle name="Index" fontName="Helvetica"/>
<paraStyle name="Heading" fontName="Helvetica" fontSize="15.0" leading="19" spaceBefore="12.0" spaceAfter="6.0"/>
<paraStyle name="terp_header" fontName="Helvetica-Bold" fontSize="12.0" leading="15" alignment="LEFT" spaceBefore="12.0" spaceAfter="6.0"/>
<paraStyle name="terp_default_8" rightIndent="0.0" leftIndent="0.0" fontName="Helvetica" fontSize="8.0" leading="10" alignment="LEFT" spaceBefore="0.0" spaceAfter="0.0"/>
<paraStyle name="Footer" fontName="Helvetica"/>
<paraStyle name="Horizontal Line" fontName="Helvetica" fontSize="6.0" leading="8" spaceBefore="0.0" spaceAfter="14.0"/>
<paraStyle name="Heading 9" fontName="Helvetica-Bold" fontSize="75%" leading="NaN" spaceBefore="12.0" spaceAfter="6.0"/>
<paraStyle name="terp_tblheader_General" fontName="Helvetica-Bold" fontSize="8.0" leading="10" alignment="LEFT" spaceBefore="6.0" spaceAfter="6.0"/>
<paraStyle name="terp_tblheader_Details" fontName="Helvetica-Bold" fontSize="9.0" leading="11" alignment="LEFT" spaceBefore="6.0" spaceAfter="6.0"/>
<paraStyle name="terp_default_Bold_8" rightIndent="0.0" leftIndent="0.0" fontName="Helvetica-Bold" fontSize="8.0" leading="10" alignment="LEFT" spaceBefore="0.0" spaceAfter="0.0"/>
<paraStyle name="terp_tblheader_General_Centre" fontName="Helvetica-Bold" fontSize="8.0" leading="10" alignment="CENTER" spaceBefore="6.0" spaceAfter="6.0"/>
<paraStyle name="terp_tblheader_General_Right" fontName="Helvetica-Bold" fontSize="8.0" leading="10" alignment="RIGHT" spaceBefore="6.0" spaceAfter="6.0"/>
<paraStyle name="terp_tblheader_Details_Centre" fontName="Helvetica-Bold" fontSize="9.0" leading="11" alignment="CENTER" spaceBefore="6.0" spaceAfter="6.0"/>
<paraStyle name="terp_tblheader_Details_Right" fontName="Helvetica-Bold" fontSize="9.0" leading="11" alignment="RIGHT" spaceBefore="6.0" spaceAfter="6.0"/>
<paraStyle name="terp_default_Right_8" rightIndent="0.0" leftIndent="0.0" fontName="Helvetica" fontSize="8.0" leading="10" alignment="RIGHT" spaceBefore="0.0" spaceAfter="0.0"/>
<paraStyle name="terp_default_Centre_8" rightIndent="0.0" leftIndent="0.0" fontName="Helvetica" fontSize="8.0" leading="10" alignment="CENTER" spaceBefore="0.0" spaceAfter="0.0"/>
<paraStyle name="terp_header_Right" fontName="Helvetica-Bold" fontSize="15.0" leading="19" alignment="LEFT" spaceBefore="12.0" spaceAfter="6.0"/>
<paraStyle name="terp_header_Centre" fontName="Helvetica-Bold" fontSize="12.0" leading="15" alignment="CENTER" spaceBefore="0.0" spaceAfter="6.0"/>
<paraStyle name="terp_default_address" rightIndent="0.0" leftIndent="0.0" fontName="Helvetica" fontSize="10.0" leading="13" alignment="LEFT" spaceBefore="0.0" spaceAfter="0.0"/>
<paraStyle name="terp_default_9" rightIndent="0.0" leftIndent="0.0" fontName="Helvetica" fontSize="9.0" leading="11" alignment="LEFT" spaceBefore="0.0" spaceAfter="0.0"/>
<paraStyle name="terp_default_Bold_9" rightIndent="0.0" leftIndent="0.0" fontName="Helvetica-Bold" fontSize="9.0" leading="11" alignment="LEFT" spaceBefore="0.0" spaceAfter="0.0"/>
<paraStyle name="terp_default_Centre_9" rightIndent="0.0" leftIndent="0.0" fontName="Helvetica" fontSize="9.0" leading="11" alignment="CENTER" spaceBefore="0.0" spaceAfter="0.0"/>
<paraStyle name="terp_default_Right_9" rightIndent="0.0" leftIndent="0.0" fontName="Helvetica" fontSize="9.0" leading="11" alignment="RIGHT" spaceBefore="0.0" spaceAfter="0.0"/>
<paraStyle name="terp_default_Bold_Right_9" rightIndent="0.0" leftIndent="0.0" fontName="Helvetica-Bold" fontSize="9.0" leading="11" alignment="RIGHT" spaceBefore="0.0" spaceAfter="0.0"/>
<paraStyle name="terp_default_2" rightIndent="0.0" leftIndent="0.0" fontName="Helvetica" fontSize="2.0" leading="3" alignment="LEFT" spaceBefore="0.0" spaceAfter="0.0"/>
<paraStyle name="terp_default_White_2" rightIndent="0.0" leftIndent="0.0" fontName="Helvetica" fontSize="2.0" leading="3" alignment="LEFT" spaceBefore="0.0" spaceAfter="0.0" textColor="#ffffff"/>
<paraStyle name="terp_default_Note" rightIndent="0.0" leftIndent="9.0" fontName="Helvetica-Oblique" fontSize="8.0" leading="10" alignment="LEFT" spaceBefore="0.0" spaceAfter="0.0"/>
<paraStyle name="Table" fontName="Helvetica" fontSize="10.0" leading="13" spaceBefore="6.0" spaceAfter="6.0"/>
<paraStyle name="terp_header_left" fontName="Helvetica-Bold" fontSize="10.0" leading="15" alignment="LEFT" spaceBefore="0.0" spaceAfter="6.0"/>
<images/>
</stylesheet>
<story>
<para style="terp_header_Centre">
<font color="white"> </font>
</para>
<para style="terp_default_8">[[ repeatIn(objects,'requisition') ]]</para>
<para style="P3">Purchase for Requisitions [[ requisition.name ]]</para>
<para style="terp_header_Centre">
<font color="white"> </font>
</para>
<blockTable colWidths="159.0,159.0,106.0,106.0" style="Table1">
<tr>
<td>
<para style="terp_tblheader_General_Centre">Requisition Reference</para>
</td>
<td>
<para style="terp_tblheader_General_Centre">Requisition Date</para>
</td>
<td>
<para style="terp_tblheader_General_Centre">Type</para>
</td>
<td>
<para style="terp_tblheader_General_Centre">Origin</para>
</td>
</tr>
<tr>
<td>
<para style="terp_default_Centre_8">[[ requisition.name ]]</para>
</td>
<td>
<para style="terp_default_Centre_8">[[ requisition.date_start ]]</para>
</td>
<td>
<para style="terp_default_Centre_8">[[ requisition.exclusive=='multiple' and 'Multiple Requisitions' or requisition.exclusive=='exclusive' and 'Purchase Requisitions (exclusive)' ]]</para>
</td>
<td>
<para style="terp_default_Centre_8">[[ requisition.origin ]]</para>
</td>
</tr>
</blockTable>
<para style="terp_default_Centre_8">
<font color="white"> </font>
</para>
<para style="terp_default_Centre_8">
<font color="white"> </font>
</para>
<section>
<para style="terp_header_left">Product Detail</para>
<blockTable colWidths="177.0,177.0,177.0" style="Table2">[[ requisition.line_ids or removeParentNode('section') ]]
<tr>
<td>
<para style="terp_tblheader_Details_Centre">Description</para>
</td>
<td>
<para style="terp_tblheader_Details_Centre">Qty</para>
</td>
<td>
<para style="terp_tblheader_Details_Centre">Product UoM</para>
</td>
</tr>
<tr><para style="terp_default_8">[[ repeatIn(requisition.line_ids,'line_ids') ]]</para>
<td>
<para style="terp_default_Centre_8">[[ line_ids.product_id.name ]]</para>
</td>
<td>
<para style="terp_default_Centre_8">[[ line_ids.product_qty ]]</para>
</td>
<td>
<para style="terp_default_Centre_8">[[ line_ids.product_uom_id.category_id.name ]]</para>
</td>
</tr>
</blockTable>
</section>
<para style="terp_default_Centre_8">
<font color="white"> </font>
</para>
<para style="terp_default_Centre_8">
<font color="white"> </font>
</para>
<section>
<para style="terp_header_left">Quotation Detail</para>
<blockTable colWidths="133.0,163.0,235.0" style="Table3">[[ requisition.purchase_ids or removeParentNode('section') ]]
<tr>
<td>
<para style="terp_tblheader_Details_Centre">Order Reference</para>
</td>
<td>
<para style="terp_tblheader_Details_Centre">Date Ordered</para>
</td>
<td>
<para style="terp_tblheader_Details_Centre">Supplier</para>
</td>
</tr>
<tr><para style="P2">[[ repeatIn(requisition.purchase_ids,'purchase_ids') ]]</para>
<td>
<para style="terp_default_Centre_8">[[ purchase_ids.name ]]</para>
</td>
<td>
<para style="terp_default_Centre_8">[[ purchase_ids.date_order ]]</para>
</td>
<td>
<para style="terp_default_Centre_8">[[ purchase_ids.partner_address_id.partner_id.name ]]</para>
</td>
</tr>
</blockTable>
</section>
<para style="P3">
<font color="white"> </font>
</para>
<para style="P4">
<font color="white"> </font>
</para>
</story>
</document>

View File

@ -0,0 +1,37 @@
# -*- coding: utf-8 -*-
##############################################################################
#
# OpenERP, Open Source Management Solution
# Copyright (C) 2004-2010 Tiny SPRL (<http://tiny.be>).
#
# 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 <http://www.gnu.org/licenses/>.
#
##############################################################################
import time
from report import report_sxw
from osv import osv
import pooler
class requisition(report_sxw.rml_parse):
def __init__(self, cr, uid, name, context):
super(requisition, self).__init__(cr, uid, name, context=context)
self.localcontext.update({
'time': time,
})
report_sxw.report_sxw('report.purchase.requisition','purchase.requisition','addons/purchase_requisition/report/purchase_requisition.rml',parser=requisition)
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

View File

@ -92,7 +92,7 @@ class purchase_requisition_partner(osv.osv_memory):
pricelist_id = partner.property_product_pricelist_purchase and partner.property_product_pricelist_purchase.id or False
price = pricelist_obj.price_get(cr, uid, [pricelist_id], line.product_id.id, line.product_qty, False, {'uom': uom_id})[pricelist_id]
product = prod_obj.browse(cr, uid, line.product_id.id, context=context)
location_id = self.pool.get('stock.warehouse').read(cr, uid, [tender.warehouse_id.id], ['lot_input_id'])[0]['lot_input_id'][0]
purchase_order_line= {
'name': product.partner_ref,
@ -118,6 +118,10 @@ class purchase_requisition_partner(osv.osv_memory):
'company_id': tender.company_id.id,
'fiscal_position': partner.property_account_position and partner.property_account_position.id or False,
'requisition_id':tender.id,
'notes':tender.description,
'warehouse_id':tender.warehouse_id.id and tender.warehouse_id.id ,
'location_id':location_id,
'company_id':tender.company_id.id,
})
order_ids=[]
for order_line in list_line:

View File

@ -12,7 +12,7 @@
<separator string="" colspan="4" />
<group colspan="4" col="6">
<button icon="gtk-cancel" special="cancel" string="_Cancel"/>
<button icon="gtk-ok" name="create_order" string="Create Orders" type="object"/>
<button icon="gtk-ok" name="create_order" string="Create Quotation" type="object"/>
</group>
</form>
</field>