diff --git a/ext/custom-addons/sale_order_optional/__init__.py b/ext/custom-addons/sale_order_optional/__init__.py new file mode 100755 index 00000000..f003963c --- /dev/null +++ b/ext/custom-addons/sale_order_optional/__init__.py @@ -0,0 +1,19 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +############################################################################## + +import sale_order_optional diff --git a/ext/custom-addons/sale_order_optional/__openerp__.py b/ext/custom-addons/sale_order_optional/__openerp__.py new file mode 100755 index 00000000..b364af2e --- /dev/null +++ b/ext/custom-addons/sale_order_optional/__openerp__.py @@ -0,0 +1,39 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# 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 . +# +############################################################################## + +{ + 'name': "Optional Lines for Sale Orders", + 'version': "1.0", + 'category': "Sales", + 'description': """ + This addon adds optional sale order lines. + """, + 'author': "Camadeus GmbH", + 'website': "http://www.camadeus.at", + 'css': [], + 'images': [], + 'depends': ['sale'], + 'data': ['sale_order_optional_view.xml', + 'sale_order_optional_data.xml', + ], + 'installable': True, + 'auto_install': False, + 'application': False, +} + +# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: diff --git a/ext/custom-addons/sale_order_optional/sale_order_optional.py b/ext/custom-addons/sale_order_optional/sale_order_optional.py new file mode 100644 index 00000000..f1db367a --- /dev/null +++ b/ext/custom-addons/sale_order_optional/sale_order_optional.py @@ -0,0 +1,135 @@ +# -*- encoding: utf-8 -*- +############################################################################## +# +# OpenERP, Open Source Management Solution +# Copyright (C) 2004-2009 Tiny SPRL (). All Rights Reserved +# $Id$ +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# +############################################################################## + +from openerp.osv import fields, osv +import openerp.addons.decimal_precision as dp + +class sale_order(osv.osv): + _inherit = "sale.order" + + def _amount_line_tax(self, cr, uid, line, context=None): + val = 0.0 + if not line.optional: + for c in self.pool.get('account.tax').compute_all(cr, uid, line.tax_id, line.price_unit * (1-(line.discount or 0.0)/100.0), line.product_uom_qty, line.product_id, line.order_id.partner_id)['taxes']: + val += c.get('amount', 0.0) + return val + + def _amount_all(self, cr, uid, ids, field_name, arg, context=None): + cur_obj = self.pool.get('res.currency') + res = {} + for order in self.browse(cr, uid, ids, context=context): + res[order.id] = { + 'amount_untaxed': 0.0, + 'amount_tax': 0.0, + 'amount_total': 0.0, + } + val = val1 = 0.0 + cur = order.pricelist_id.currency_id + for line in order.order_line: + val1 += line.price_subtotal + val += self._amount_line_tax(cr, uid, line, context=context) + res[order.id]['amount_tax'] = cur_obj.round(cr, uid, cur, val) + res[order.id]['amount_untaxed'] = cur_obj.round(cr, uid, cur, val1) + res[order.id]['amount_total'] = res[order.id]['amount_untaxed'] + res[order.id]['amount_tax'] + return res + + def _amount_all_wrapper(self, cr, uid, ids, field_name, arg, context=None): + """ Wrapper because of direct method passing as parameter for function fields """ + return self._amount_all(cr, uid, ids, field_name, arg, context=context) + + def _get_order(self, cr, uid, ids, context=None): + result = {} + for line in self.pool.get('sale.order.line').browse(cr, uid, ids, context=context): + result[line.order_id.id] = True + return result.keys() + + _columns = { + 'amount_untaxed': fields.function(_amount_all_wrapper, digits_compute=dp.get_precision('Account'), string='Untaxed Amount', + store={ + 'sale.order': (lambda self, cr, uid, ids, c={}: ids, ['order_line'], 10), + 'sale.order.line': (_get_order, ['price_unit', 'tax_id', 'discount', 'product_uom_qty'], 10), + }, + multi='sums', help="The amount without tax.", track_visibility='always'), + 'amount_tax': fields.function(_amount_all_wrapper, digits_compute=dp.get_precision('Account'), string='Taxes', + store={ + 'sale.order': (lambda self, cr, uid, ids, c={}: ids, ['order_line'], 10), + 'sale.order.line': (_get_order, ['price_unit', 'tax_id', 'discount', 'product_uom_qty'], 10), + }, + multi='sums', help="The tax amount."), + 'amount_total': fields.function(_amount_all_wrapper, digits_compute=dp.get_precision('Account'), string='Total', + store={ + 'sale.order': (lambda self, cr, uid, ids, c={}: ids, ['order_line'], 10), + 'sale.order.line': (_get_order, ['price_unit', 'tax_id', 'discount', 'product_uom_qty'], 10), + }, + multi='sums', help="The total amount."), + } + +class sale_order_line(osv.osv): + _inherit = 'sale.order.line' + + def _fnct_line_invoiced(self, cr, uid, ids, field_name, args, context=None): + res = dict.fromkeys(ids, False) + for this in self.browse(cr, uid, ids, context=context): + res[this.id] = this.invoice_lines and \ + all(iline.invoice_id.state != 'cancel' for iline in this.invoice_lines) or \ + this.optional + return res + + def _order_lines_from_invoice(self, cr, uid, ids, context=None): + # direct access to the m2m table is the less convoluted way to achieve this (and is ok ACL-wise) + cr.execute("""SELECT DISTINCT sol.id FROM sale_order_invoice_rel rel JOIN + sale_order_line sol ON (sol.order_id = rel.order_id) + WHERE rel.invoice_id = ANY(%s)""", (list(ids),)) + return [i[0] for i in cr.fetchall()] + + def _amount_line(self, cr, uid, ids, field_name, arg, context=None): + tax_obj = self.pool.get('account.tax') + cur_obj = self.pool.get('res.currency') + res = {} + if context is None: + context = {} + for line in self.browse(cr, uid, ids, context=context): + if not line.optional: + price = line.price_unit * (1 - (line.discount or 0.0) / 100.0) + taxes = tax_obj.compute_all(cr, uid, line.tax_id, price, line.product_uom_qty, line.product_id, line.order_id.partner_id) + cur = line.order_id.pricelist_id.currency_id + res[line.id] = cur_obj.round(cr, uid, cur, taxes['total']) + else: + res[line.id] = 0 + return res + + _columns = { + 'invoiced': fields.function(_fnct_line_invoiced, string='Invoiced', type='boolean', + store={ + 'account.invoice': (_order_lines_from_invoice, ['state'], 10), + 'sale.order.line': (lambda self,cr,uid,ids,ctx=None: ids, ['invoice_lines'], 10) + }), + 'price_subtotal': fields.function(_amount_line, string='Subtotal', digits_compute= dp.get_precision('Account')), + 'optional': fields.boolean('Optional'), + } + + def _prepare_order_line_invoice_line(self, cr, uid, line, account_id=False, context=None): + if not line.optional: + return super(sale_order_line, self)._prepare_order_line_invoice_line(cr, uid, line, account_id, context=context) + else: + return False + \ No newline at end of file diff --git a/ext/custom-addons/sale_order_optional/sale_order_optional_data.xml b/ext/custom-addons/sale_order_optional/sale_order_optional_data.xml new file mode 100644 index 00000000..d13a406f --- /dev/null +++ b/ext/custom-addons/sale_order_optional/sale_order_optional_data.xml @@ -0,0 +1,6 @@ + + + + + + diff --git a/ext/custom-addons/sale_order_optional/sale_order_optional_view.xml b/ext/custom-addons/sale_order_optional/sale_order_optional_view.xml new file mode 100644 index 00000000..66056673 --- /dev/null +++ b/ext/custom-addons/sale_order_optional/sale_order_optional_view.xml @@ -0,0 +1,17 @@ + + + + + + sale.order.form.optional + sale.order + + + + + + + + + + diff --git a/ext/custom-addons/sale_order_optional/static/description/icon.png b/ext/custom-addons/sale_order_optional/static/description/icon.png new file mode 100644 index 00000000..fd7ee3b9 Binary files /dev/null and b/ext/custom-addons/sale_order_optional/static/description/icon.png differ diff --git a/ext/custom-addons/sale_order_reminder/__init__.py b/ext/custom-addons/sale_order_reminder/__init__.py new file mode 100755 index 00000000..0ff87ab2 --- /dev/null +++ b/ext/custom-addons/sale_order_reminder/__init__.py @@ -0,0 +1,19 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +############################################################################## + +import sale_order_reminder diff --git a/ext/custom-addons/sale_order_reminder/__openerp__.py b/ext/custom-addons/sale_order_reminder/__openerp__.py new file mode 100755 index 00000000..bbf29c4d --- /dev/null +++ b/ext/custom-addons/sale_order_reminder/__openerp__.py @@ -0,0 +1,41 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# 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 . +# +############################################################################## + +{ + 'name': "Reminder for Sale Orders", + 'version': "1.0", + 'category': "Sales", + 'description': """ + This addon adds the field 'offer_valid_until' in the sale order. If this date is passed and the order is still in state 'draft' or 'sent', then + a reminder email is sent to the sales person every day. + """, + 'author': "Camadeus GmbH", + 'website': "http://www.camadeus.at", + 'css': [], + 'images': [], + 'depends': ['sale'], + 'data': ['sale_order_reminder_view.xml', + 'sale_order_reminder_data.xml', + 'email_template.xml', + ], + 'installable': True, + 'auto_install': False, + 'application': False, +} + +# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: diff --git a/ext/custom-addons/sale_order_reminder/email_template.xml b/ext/custom-addons/sale_order_reminder/email_template.xml new file mode 100644 index 00000000..512bc06f --- /dev/null +++ b/ext/custom-addons/sale_order_reminder/email_template.xml @@ -0,0 +1,46 @@ + + + + + + + + + Erinnerung: Angebot + ${(object.user_id and object.user_id.email or '')|safe} + Erinnerung: Angebot ${object.name} + ${object.user_id and object.user_id.partner_id.id} + + + +

Erinnerung für folgendes offenes Angebot:

+ +

+ + + + + + + + + + + + + + + + + +
Name:${object.name}
Datum: ${object.date_order}
Kunde: ${object.partner_id.display_name}
Auftragsvolumen (netto): ${object.amount_untaxed}
+ +

+
+ +]]>
+
+
+
diff --git a/ext/custom-addons/sale_order_reminder/sale_order_reminder.py b/ext/custom-addons/sale_order_reminder/sale_order_reminder.py new file mode 100644 index 00000000..a10e1d14 --- /dev/null +++ b/ext/custom-addons/sale_order_reminder/sale_order_reminder.py @@ -0,0 +1,68 @@ +# -*- encoding: utf-8 -*- +############################################################################## +# +# OpenERP, Open Source Management Solution +# Copyright (C) 2004-2009 Tiny SPRL (). All Rights Reserved +# $Id$ +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# +############################################################################## + +from openerp import models, fields, api, _ +from datetime import datetime, timedelta +from openerp.tools import DEFAULT_SERVER_DATE_FORMAT as DATE_FORMAT + +class res_company(models.Model): + _inherit = 'res.company' + + sale_offer_days = fields.Integer(string='Tage Gültigkeit Angebot', default=14) + +class sale_order(models.Model): + _inherit = 'sale.order' + + @api.model + def _offer_valid_until(self): + user = self.env['res.users'].browse(self._uid) + + now = datetime.now() + res = now + timedelta(days=user.company_id.sale_offer_days) + return res.strftime(DATE_FORMAT) + + + offer_valid_until = fields.Date(string='Angebot gültig bis', index=True, + readonly=True, states={'draft': [('readonly', False)], 'sent': [('readonly', False)]}, + default=_offer_valid_until) + + @api.model + def order_reminder_job(self): + today = fields.Date.today() + orders = self.search([('offer_valid_until','<',today),('state','in',('draft','sent')),('user_id','!=',False)]) + template_id = self.env['ir.model.data'].xmlid_to_res_id('sale_order_reminder.email_template_sale_reminder') + context = {'append_link': True} + for order in orders: + res = self.pool.get('email.template').send_mail(self._cr, self._uid, template_id, order.id, True, context=context) + return True + +class mail_mail(models.Model): + _inherit = 'mail.mail' + + def create(self, cr, uid, vals, context=None): + # notification field: set if it comes from order reminder job + if context is None: + context = {} + + if context.get('append_link'): + vals['notification'] = True + return super(mail_mail, self).create(cr, uid, vals, context=context) \ No newline at end of file diff --git a/ext/custom-addons/sale_order_reminder/sale_order_reminder_data.xml b/ext/custom-addons/sale_order_reminder/sale_order_reminder_data.xml new file mode 100644 index 00000000..044a3708 --- /dev/null +++ b/ext/custom-addons/sale_order_reminder/sale_order_reminder_data.xml @@ -0,0 +1,16 @@ + + + + + + Reminder for Sale Orders + 1 + days + -1 + + + + + + + diff --git a/ext/custom-addons/sale_order_reminder/sale_order_reminder_view.xml b/ext/custom-addons/sale_order_reminder/sale_order_reminder_view.xml new file mode 100644 index 00000000..589e3c62 --- /dev/null +++ b/ext/custom-addons/sale_order_reminder/sale_order_reminder_view.xml @@ -0,0 +1,31 @@ + + + + + + sale_order_valid_until_form + sale.order + + + + + + + 20 + # + + + "res_company_order_days_form" + res.company + + + + + + + + + + + + diff --git a/ext/custom-addons/sale_order_reminder/static/description/icon.png b/ext/custom-addons/sale_order_reminder/static/description/icon.png new file mode 100644 index 00000000..fd7ee3b9 Binary files /dev/null and b/ext/custom-addons/sale_order_reminder/static/description/icon.png differ diff --git a/setup/lib/config_at.py b/setup/lib/config_at.py index eb9dc884..cea6cc6e 100644 --- a/setup/lib/config_at.py +++ b/setup/lib/config_at.py @@ -156,4 +156,6 @@ class Config(): #'sale', #'cam_hr_overtime', #'cam_hr', + #'sale_order_optiona', + #'sale_order_reminder', ]