diff --git a/addons/account_cancel/i18n/da.po b/addons/account_cancel/i18n/da.po index db0de0e5bae..2f0269b2d93 100644 --- a/addons/account_cancel/i18n/da.po +++ b/addons/account_cancel/i18n/da.po @@ -8,19 +8,19 @@ msgstr "" "Project-Id-Version: openobject-addons\n" "Report-Msgid-Bugs-To: FULL NAME \n" "POT-Creation-Date: 2012-12-21 17:05+0000\n" -"PO-Revision-Date: 2011-11-08 10:42+0000\n" -"Last-Translator: OpenERP Danmark / Mikhael Saxtorph \n" +"PO-Revision-Date: 2013-09-26 21:19+0000\n" +"Last-Translator: Morten Schou \n" "Language-Team: Danish \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2013-09-12 06:17+0000\n" -"X-Generator: Launchpad (build 16761)\n" +"X-Launchpad-Export-Date: 2013-09-27 05:49+0000\n" +"X-Generator: Launchpad (build 16774)\n" #. module: account_cancel #: view:account.invoice:0 msgid "Cancel" -msgstr "" +msgstr "Annuller" #~ msgid "Account Cancel" #~ msgstr "Annuller post" diff --git a/addons/account_test/i18n/zh_CN.po b/addons/account_test/i18n/zh_CN.po index 71d962610b7..67aeab3353e 100644 --- a/addons/account_test/i18n/zh_CN.po +++ b/addons/account_test/i18n/zh_CN.po @@ -8,14 +8,14 @@ msgstr "" "Project-Id-Version: openobject-addons\n" "Report-Msgid-Bugs-To: FULL NAME \n" "POT-Creation-Date: 2012-12-21 17:05+0000\n" -"PO-Revision-Date: 2013-03-21 19:22+0000\n" -"Last-Translator: Liuming \n" +"PO-Revision-Date: 2013-09-24 02:46+0000\n" +"Last-Translator: DWXXX \n" "Language-Team: Chinese (Simplified) \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2013-09-12 06:40+0000\n" -"X-Generator: Launchpad (build 16761)\n" +"X-Launchpad-Export-Date: 2013-09-25 05:28+0000\n" +"X-Generator: Launchpad (build 16771)\n" #. module: account_test #: view:accounting.assert.test:0 @@ -106,7 +106,7 @@ msgstr "" #. module: account_test #: view:accounting.assert.test:0 msgid "Description" -msgstr "" +msgstr "描述" #. module: account_test #: model:accounting.assert.test,desc:account_test.account_test_06_1 @@ -123,13 +123,13 @@ msgstr "" #: model:ir.actions.report.xml,name:account_test.account_assert_test_report #: model:ir.ui.menu,name:account_test.menu_action_license msgid "Accounting Tests" -msgstr "" +msgstr "帐户测试" #. module: account_test #: code:addons/account_test/report/account_test_report.py:74 #, python-format msgid "The test was passed successfully" -msgstr "" +msgstr "测试通过" #. module: account_test #: field:accounting.assert.test,active:0 @@ -155,7 +155,7 @@ msgstr "" #. module: account_test #: field:accounting.assert.test,code_exec:0 msgid "Python code" -msgstr "" +msgstr "Python代码" #. module: account_test #: model:accounting.assert.test,desc:account_test.account_test_07 @@ -209,7 +209,7 @@ msgstr "" #. module: account_test #: view:accounting.assert.test:0 msgid "Python Code" -msgstr "" +msgstr "Python代码" #. module: account_test #: model:ir.actions.act_window,help:account_test.action_accounting_assert diff --git a/addons/auth_signup/i18n/zh_TW.po b/addons/auth_signup/i18n/zh_TW.po new file mode 100644 index 00000000000..b16d2be5abf --- /dev/null +++ b/addons/auth_signup/i18n/zh_TW.po @@ -0,0 +1,279 @@ +# Chinese (Traditional) translation for openobject-addons +# Copyright (c) 2013 Rosetta Contributors and Canonical Ltd 2013 +# This file is distributed under the same license as the openobject-addons package. +# FIRST AUTHOR , 2013. +# +msgid "" +msgstr "" +"Project-Id-Version: openobject-addons\n" +"Report-Msgid-Bugs-To: FULL NAME \n" +"POT-Creation-Date: 2012-12-21 17:05+0000\n" +"PO-Revision-Date: 2013-09-19 09:40+0000\n" +"Last-Translator: FULL NAME \n" +"Language-Team: Chinese (Traditional) \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Launchpad-Export-Date: 2013-09-20 05:38+0000\n" +"X-Generator: Launchpad (build 16765)\n" + +#. module: auth_signup +#: field:res.partner,signup_type:0 +msgid "Signup Token Type" +msgstr "" + +#. module: auth_signup +#: field:base.config.settings,auth_signup_uninvited:0 +msgid "Allow external users to sign up" +msgstr "允許外部使用者註冊" + +#. module: auth_signup +#. openerp-web +#: code:addons/auth_signup/static/src/xml/auth_signup.xml:19 +#, python-format +msgid "Confirm Password" +msgstr "確認密碼" + +#. module: auth_signup +#: help:base.config.settings,auth_signup_uninvited:0 +msgid "If unchecked, only invited users may sign up." +msgstr "如果未勾選,只有被邀請的使用者可以註冊" + +#. module: auth_signup +#: model:ir.model,name:auth_signup.model_base_config_settings +msgid "base.config.settings" +msgstr "" + +#. module: auth_signup +#: code:addons/auth_signup/res_users.py:266 +#, python-format +msgid "Cannot send email: user has no email address." +msgstr "無法送出email:使用者沒有email 地址" + +#. module: auth_signup +#. openerp-web +#: code:addons/auth_signup/static/src/xml/auth_signup.xml:27 +#: code:addons/auth_signup/static/src/xml/auth_signup.xml:31 +#, python-format +msgid "Reset password" +msgstr "重設密碼" + +#. module: auth_signup +#: field:base.config.settings,auth_signup_template_user_id:0 +msgid "Template user for new users created through signup" +msgstr "" + +#. module: auth_signup +#: model:email.template,subject:auth_signup.reset_password_email +msgid "Password reset" +msgstr "" + +#. module: auth_signup +#. openerp-web +#: code:addons/auth_signup/static/src/js/auth_signup.js:120 +#, python-format +msgid "Please enter a password and confirm it." +msgstr "" + +#. module: auth_signup +#: view:res.users:0 +msgid "Send an email to the user to (re)set their password." +msgstr "" + +#. module: auth_signup +#. openerp-web +#: code:addons/auth_signup/static/src/xml/auth_signup.xml:26 +#: code:addons/auth_signup/static/src/xml/auth_signup.xml:29 +#, python-format +msgid "Sign Up" +msgstr "" + +#. module: auth_signup +#: selection:res.users,state:0 +msgid "New" +msgstr "" + +#. module: auth_signup +#: code:addons/auth_signup/res_users.py:258 +#, python-format +msgid "Mail sent to:" +msgstr "" + +#. module: auth_signup +#: field:res.users,state:0 +msgid "Status" +msgstr "" + +#. module: auth_signup +#: model:email.template,body_html:auth_signup.reset_password_email +msgid "" +"\n" +"

A password reset was requested for the OpenERP account linked to this " +"email.

\n" +"\n" +"

You may change your password by following this link.

\n" +"\n" +"

Note: If you do not expect this, you can safely ignore this email.

" +msgstr "" + +#. module: auth_signup +#. openerp-web +#: code:addons/auth_signup/static/src/js/auth_signup.js:114 +#, python-format +msgid "Please enter a name." +msgstr "" + +#. module: auth_signup +#: model:ir.model,name:auth_signup.model_res_users +msgid "Users" +msgstr "" + +#. module: auth_signup +#: field:res.partner,signup_url:0 +msgid "Signup URL" +msgstr "" + +#. module: auth_signup +#. openerp-web +#: code:addons/auth_signup/static/src/js/auth_signup.js:117 +#, python-format +msgid "Please enter a username." +msgstr "" + +#. module: auth_signup +#: selection:res.users,state:0 +msgid "Active" +msgstr "" + +#. module: auth_signup +#: code:addons/auth_signup/res_users.py:270 +#, python-format +msgid "" +"Cannot send email: no outgoing email server configured.\n" +"You can configure it under Settings/General Settings." +msgstr "" + +#. module: auth_signup +#. openerp-web +#: code:addons/auth_signup/static/src/xml/auth_signup.xml:12 +#, python-format +msgid "Username" +msgstr "" + +#. module: auth_signup +#. openerp-web +#: code:addons/auth_signup/static/src/xml/auth_signup.xml:8 +#, python-format +msgid "Name" +msgstr "" + +#. module: auth_signup +#. openerp-web +#: code:addons/auth_signup/static/src/js/auth_signup.js:173 +#, python-format +msgid "Please enter a username or email address." +msgstr "" + +#. module: auth_signup +#: selection:res.users,state:0 +msgid "Resetting Password" +msgstr "" + +#. module: auth_signup +#. openerp-web +#: code:addons/auth_signup/static/src/xml/auth_signup.xml:13 +#, python-format +msgid "Username (Email)" +msgstr "" + +#. module: auth_signup +#: field:res.partner,signup_expiration:0 +msgid "Signup Expiration" +msgstr "" + +#. module: auth_signup +#: help:base.config.settings,auth_signup_reset_password:0 +msgid "This allows users to trigger a password reset from the Login page." +msgstr "" + +#. module: auth_signup +#. openerp-web +#: code:addons/auth_signup/static/src/xml/auth_signup.xml:25 +#, python-format +msgid "Log in" +msgstr "" + +#. module: auth_signup +#: field:res.partner,signup_valid:0 +msgid "Signup Token is Valid" +msgstr "" + +#. module: auth_signup +#. openerp-web +#: code:addons/auth_signup/static/src/js/auth_signup.js:111 +#: code:addons/auth_signup/static/src/js/auth_signup.js:114 +#: code:addons/auth_signup/static/src/js/auth_signup.js:117 +#: code:addons/auth_signup/static/src/js/auth_signup.js:120 +#: code:addons/auth_signup/static/src/js/auth_signup.js:123 +#: code:addons/auth_signup/static/src/js/auth_signup.js:170 +#: code:addons/auth_signup/static/src/js/auth_signup.js:173 +#, python-format +msgid "Login" +msgstr "" + +#. module: auth_signup +#. openerp-web +#: code:addons/auth_signup/static/src/js/auth_signup.js:97 +#, python-format +msgid "Invalid signup token" +msgstr "" + +#. module: auth_signup +#. openerp-web +#: code:addons/auth_signup/static/src/js/auth_signup.js:123 +#, python-format +msgid "Passwords do not match; please retype them." +msgstr "" + +#. module: auth_signup +#. openerp-web +#: code:addons/auth_signup/static/src/js/auth_signup.js:111 +#: code:addons/auth_signup/static/src/js/auth_signup.js:170 +#, python-format +msgid "No database selected !" +msgstr "" + +#. module: auth_signup +#: view:res.users:0 +msgid "Reset Password" +msgstr "" + +#. module: auth_signup +#: field:base.config.settings,auth_signup_reset_password:0 +msgid "Enable password reset from Login page" +msgstr "" + +#. module: auth_signup +#. openerp-web +#: code:addons/auth_signup/static/src/xml/auth_signup.xml:30 +#, python-format +msgid "Back to Login" +msgstr "" + +#. module: auth_signup +#. openerp-web +#: code:addons/auth_signup/static/src/xml/auth_signup.xml:22 +#, python-format +msgid "Sign up" +msgstr "" + +#. module: auth_signup +#: model:ir.model,name:auth_signup.model_res_partner +msgid "Partner" +msgstr "" + +#. module: auth_signup +#: field:res.partner,signup_token:0 +msgid "Signup Token" +msgstr "" diff --git a/addons/crm/crm_lead.py b/addons/crm/crm_lead.py index 9d17526c19f..fcfec50d344 100644 --- a/addons/crm/crm_lead.py +++ b/addons/crm/crm_lead.py @@ -298,7 +298,7 @@ class crm_lead(format_address, osv.osv): 'company_id': lambda s, cr, uid, c: s.pool.get('res.company')._company_default_get(cr, uid, 'crm.lead', context=c), 'priority': lambda *a: crm.AVAILABLE_PRIORITIES[2][0], 'color': 0, - 'date_last_stage_update': fields.datetime.now(), + 'date_last_stage_update': fields.datetime.now, } _sql_constraints = [ diff --git a/addons/crm_claim/crm_claim.py b/addons/crm_claim/crm_claim.py index c655ce2c12b..a3b09c272f6 100644 --- a/addons/crm_claim/crm_claim.py +++ b/addons/crm_claim/crm_claim.py @@ -108,7 +108,7 @@ class crm_claim(osv.osv): _defaults = { 'user_id': lambda s, cr, uid, c: uid, 'section_id': lambda s, cr, uid, c: s._get_default_section_id(cr, uid, c), - 'date': fields.datetime.now(), + 'date': fields.datetime.now, 'company_id': lambda s, cr, uid, c: s.pool.get('res.company')._company_default_get(cr, uid, 'crm.case', context=c), 'priority': lambda *a: crm.AVAILABLE_PRIORITIES[2][0], 'active': lambda *a: 1, diff --git a/addons/crm_helpdesk/crm_helpdesk.py b/addons/crm_helpdesk/crm_helpdesk.py index 03e6a243851..80a86c87c7c 100644 --- a/addons/crm_helpdesk/crm_helpdesk.py +++ b/addons/crm_helpdesk/crm_helpdesk.py @@ -80,7 +80,7 @@ class crm_helpdesk(osv.osv): 'active': lambda *a: 1, 'user_id': lambda s, cr, uid, c: uid, 'state': lambda *a: 'draft', - 'date': lambda *a: fields.datetime.now(), + 'date': fields.datetime.now, 'company_id': lambda s, cr, uid, c: s.pool.get('res.company')._company_default_get(cr, uid, 'crm.helpdesk', context=c), 'priority': lambda *a: crm.AVAILABLE_PRIORITIES[2][0], } diff --git a/addons/hr_expense/hr_expense_demo.xml b/addons/hr_expense/hr_expense_demo.xml index b7b6cd37956..aa490eddbea 100644 --- a/addons/hr_expense/hr_expense_demo.xml +++ b/addons/hr_expense/hr_expense_demo.xml @@ -15,6 +15,7 @@ + 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 @@ -26,6 +27,7 @@ AT + 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 @@ -36,6 +38,7 @@ HA0 + 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 diff --git a/addons/hr_recruitment/hr_recruitment.py b/addons/hr_recruitment/hr_recruitment.py index 8664a2c1166..0f0f2785fc1 100644 --- a/addons/hr_recruitment/hr_recruitment.py +++ b/addons/hr_recruitment/hr_recruitment.py @@ -225,7 +225,7 @@ class hr_applicant(osv.Model): 'department_id': lambda s, cr, uid, c: s._get_default_department_id(cr, uid, c), 'company_id': lambda s, cr, uid, c: s.pool.get('res.company')._company_default_get(cr, uid, 'hr.applicant', context=c), 'color': 0, - 'date_last_stage_update': fields.datetime.now(), + 'date_last_stage_update': fields.datetime.now, } _group_by_full = { diff --git a/addons/im/im.py b/addons/im/im.py index f91017e1712..3c4f0bfcd14 100644 --- a/addons/im/im.py +++ b/addons/im/im.py @@ -303,7 +303,7 @@ class im_user(osv.osv): 'name': fields.function(_get_name, type='char', size=200, string="Name", store=True, readonly=True), 'assigned_name': fields.char(string="Assigned Name", size=200, required=False), 'image': fields.related('user_id', 'image_small', type='binary', string="Image", readonly=True), - 'user_id': fields.many2one("res.users", string="User", select=True, ondelete='cascade'), + 'user_id': fields.many2one("res.users", string="User", select=True, ondelete='cascade', oldname='user'), 'uuid': fields.char(string="UUID", size=50, select=True), 'im_last_received': fields.integer(string="Instant Messaging Last Received Message"), 'im_last_status': fields.boolean(strint="Instant Messaging Last Status"), diff --git a/addons/mail/mail_message.py b/addons/mail/mail_message.py index 3719dbc1c63..72ccdc83bb6 100644 --- a/addons/mail/mail_message.py +++ b/addons/mail/mail_message.py @@ -212,7 +212,7 @@ class mail_message(osv.Model): _defaults = { 'type': 'email', - 'date': fields.datetime.now(), + 'date': fields.datetime.now, 'author_id': lambda self, cr, uid, ctx=None: self._get_default_author(cr, uid, ctx), 'body': '', 'email_from': lambda self, cr, uid, ctx=None: self._get_default_from(cr, uid, ctx), diff --git a/addons/mass_mailing/__openerp__.py b/addons/mass_mailing/__openerp__.py index db7ac54263a..b8ca21c60d7 100644 --- a/addons/mass_mailing/__openerp__.py +++ b/addons/mass_mailing/__openerp__.py @@ -21,7 +21,11 @@ { 'name': 'Mass Mailing Campaigns', - 'description': """TODO""", + 'description': """ +Easily send mass mailing to your leads, opportunities or customers. Track +marketing campaigns performance to improve conversion rates. Design +professional emails and reuse templates in a few clicks. + """, 'version': '1.0', 'author': 'OpenERP', 'website': 'http://www.openerp.com', diff --git a/addons/mass_mailing/mass_mailing.py b/addons/mass_mailing/mass_mailing.py index 49ee106bc69..ad59a918203 100644 --- a/addons/mass_mailing/mass_mailing.py +++ b/addons/mass_mailing/mass_mailing.py @@ -274,7 +274,7 @@ class MassMailing(osv.Model): } _defaults = { - 'date': fields.datetime.now(), + 'date': fields.datetime.now, } diff --git a/addons/mass_mailing/static/description/app_crm.png b/addons/mass_mailing/static/description/app_crm.png new file mode 100644 index 00000000000..e20c44836ba Binary files /dev/null and b/addons/mass_mailing/static/description/app_crm.png differ diff --git a/addons/mass_mailing/static/description/app_marketing_campaign.png b/addons/mass_mailing/static/description/app_marketing_campaign.png new file mode 100644 index 00000000000..f7662587969 Binary files /dev/null and b/addons/mass_mailing/static/description/app_marketing_campaign.png differ diff --git a/addons/mass_mailing/static/description/app_website_crm.png b/addons/mass_mailing/static/description/app_website_crm.png new file mode 100644 index 00000000000..7f19f68db61 Binary files /dev/null and b/addons/mass_mailing/static/description/app_website_crm.png differ diff --git a/addons/mass_mailing/static/description/icon.png b/addons/mass_mailing/static/description/icon.png new file mode 100644 index 00000000000..6ef68f30952 Binary files /dev/null and b/addons/mass_mailing/static/description/icon.png differ diff --git a/addons/mass_mailing/static/description/index.html b/addons/mass_mailing/static/description/index.html new file mode 100644 index 00000000000..49f4d99e80f --- /dev/null +++ b/addons/mass_mailing/static/description/index.html @@ -0,0 +1,227 @@ +
+
+

Mass Mailing Made Easy

+

Design, Send, Track Emails

+
+
+ +
+
+
+

+Easily send mass mailing to your leads, opportunities or customers. Track +marketing campaigns performance to improve conversion rates. Design +professional emails and reuse templates in a few clicks. +

+ +
+
+
+ +
+
+

Send Professional Emails

+
+

+Import database of prospects or filter on +existing leads, opportunities and customers in just a few clicks. +

+Define email templates to reuse content or specific design for your newsletter. +Setup several email servers with their own IP/domain to optimise opening rates. +

+
+
+
+ +
+
+
+
+ +
+
+

Organize Marketing Campaigns

+

Design, Send, Track by Campaigns

+
+
+ +
+
+
+

+ Get real time statistics on campaigns performance to improve your + conversion rate. Track mails sent, received, opened and + answered. +

+ Easily manage your marketing campaigns, discussion groups, + leads and opportunities in one simple and powerful platform. +

+
+
+
+ +
+
+

Integrated with OpenERP Apps

+

+
+

+Get access to mass mailing features from every OpenERP app to improve +the way your users communicate. +

+Send template of emails from CRM opportunities, select leads based on +marketing segments, send jobs offers and automate answers to applicants, reuse +email template in the lead automation marketing campaigns. +

+Answers to your emails appears automatically in the history of every document with the +social network module. +

+
+
+
+ +
+
+
+
+ +
+
+

Clean Your Lead Database

+

Handle bounce and conversion rates

+
+
+ +
+
+
+

+ Get a clean lead database that improves over the time using the + performance of your mails. OpenERP handle bounce mails + efficiently, flag erroneous leads accordingly and gives you + statistics on the quality of your leads. +

+
+
+
+ +
+
+

One click emails send

+

Select any documents, send emails

+
+

+The marketing department will love working on campaigns. But you can also +give a one click mass mailing facility to all others users on their own +prospects or documents. +

+Select a few documents (e.g. leads, support tickets, suppliers, applicants, +...) and send emails to their contacts in one click, reusing existing emails +templates. +

+
+
+
+ +
+
+ +
+
+ +
+
+

Follow-up On Answers

+

Communicate efficiently with prospects

+
+
+ +
+
+
+

+The chatter feature enables you to communicate faster and more efficiently with +your customer. Get documents created automatically (leads, opportunities, +tasks, ...) based on answers to your mass mailing campaigns Follow the +discussion directly on the business documents within OpenERP or via email. +

+Get all the negotiations and discussions attached to the right document +and relevent managers notified on specific events. +

+
+
+
+ +
+
+

Campaigns Dashboard

+

Analyse the performance of your campaigns

+
+

+Get the insights you need to make smarter marketing campaign. Track statistics +per campaign: bounce rates, sent mails, best content, etc. The clear dashboards +gives you a direct overview of your campaign performance. +

+
+
+
+ +
+
+
+
+ +
+
+

Fully Integrated With Others Apps

+

Efficient mailing for every users

+
+
+
+ +

Lead Automation

+
+ +
+
+

+ Define automated actions (e.g. ask a salesperson to call, send + an email, ...) based on triggers (no activity since 20 days, + answered a promotional email, etc.) +

+ Optimize campaigns from lead to close, on every channel. Make + smarter decisions about where to invest and show the impact of + your marketing activities on your company's bottom line. +

+
+
+ +

Website Forms

+
+ +
+
+

+ Integrate a contact form in your website easily. Forms + submissions create leads automatically in OpenERP CRM. Leads + can be used in marketing campaigns. +

+
+
+ +

CRM

+
+ +
+
+

+Manage your sales funnel with no effort. Attract leads, follow-up on phone +calls and meetings. Analyse the quality of your leads to make informed +decisions and save time by integrating emails directly into the application. +

+
+
+
+ diff --git a/addons/mass_mailing/static/description/mass_mailing_campaign.png b/addons/mass_mailing/static/description/mass_mailing_campaign.png new file mode 100644 index 00000000000..961e25a5f19 Binary files /dev/null and b/addons/mass_mailing/static/description/mass_mailing_campaign.png differ diff --git a/addons/mass_mailing/static/description/mass_mailing_composer.png b/addons/mass_mailing/static/description/mass_mailing_composer.png new file mode 100644 index 00000000000..64f8996ec63 Binary files /dev/null and b/addons/mass_mailing/static/description/mass_mailing_composer.png differ diff --git a/addons/mass_mailing/static/description/mass_mailing_dashboard.png b/addons/mass_mailing/static/description/mass_mailing_dashboard.png new file mode 100644 index 00000000000..8f1ff1e95fe Binary files /dev/null and b/addons/mass_mailing/static/description/mass_mailing_dashboard.png differ diff --git a/addons/mass_mailing/static/description/mass_mailing_history.png b/addons/mass_mailing/static/description/mass_mailing_history.png new file mode 100644 index 00000000000..483e5eec09b Binary files /dev/null and b/addons/mass_mailing/static/description/mass_mailing_history.png differ diff --git a/addons/mass_mailing/static/description/mass_mailing_mailing.png b/addons/mass_mailing/static/description/mass_mailing_mailing.png new file mode 100644 index 00000000000..1bed96aed81 Binary files /dev/null and b/addons/mass_mailing/static/description/mass_mailing_mailing.png differ diff --git a/addons/mass_mailing/static/description/mass_mailing_tasks.png b/addons/mass_mailing/static/description/mass_mailing_tasks.png new file mode 100644 index 00000000000..418eebe4ab8 Binary files /dev/null and b/addons/mass_mailing/static/description/mass_mailing_tasks.png differ diff --git a/addons/point_of_sale/controllers/main.py b/addons/point_of_sale/controllers/main.py index de757238d6f..419f5bc2efa 100644 --- a/addons/point_of_sale/controllers/main.py +++ b/addons/point_of_sale/controllers/main.py @@ -82,7 +82,7 @@ class PointOfSaleController(http.Controller): """ print 'scan_item_success: ' + str(ean) - @http.route('/pos/scan_item_error_unrecognized') + @http.route('/pos/scan_item_error_unrecognized', type='json', auth='admin') def scan_item_error_unrecognized(self, ean): """ A product has been scanned without success diff --git a/addons/point_of_sale/static/src/img/minus.png b/addons/point_of_sale/static/src/img/minus.png new file mode 100644 index 00000000000..507f20384c6 Binary files /dev/null and b/addons/point_of_sale/static/src/img/minus.png differ diff --git a/addons/point_of_sale/static/src/img/plus.png b/addons/point_of_sale/static/src/img/plus.png new file mode 100644 index 00000000000..041a9d46faf Binary files /dev/null and b/addons/point_of_sale/static/src/img/plus.png differ diff --git a/addons/point_of_sale/static/src/js/db.js b/addons/point_of_sale/static/src/js/db.js index bb0acfb285c..66791bb3c8b 100644 --- a/addons/point_of_sale/static/src/js/db.js +++ b/addons/point_of_sale/static/src/js/db.js @@ -43,6 +43,7 @@ function openerp_pos_db(instance, module){ this.product_by_id = {}; this.product_by_ean13 = {}; this.product_by_category_id = {}; + this.product_by_reference = {}; this.category_by_id = {}; this.root_category_id = 0; @@ -197,6 +198,9 @@ function openerp_pos_db(instance, module){ if(product.ean13){ this.product_by_ean13[product.ean13] = product; } + if(product.default_code){ + this.product_by_reference[product.default_code] = product; + } } }, add_packagings: function(packagings){ @@ -241,6 +245,9 @@ function openerp_pos_db(instance, module){ } return undefined; }, + get_product_by_reference: function(ref){ + return this.product_by_reference[ref]; + }, get_product_by_category: function(category_id){ var product_ids = this.product_by_category_id[category_id]; var list = []; diff --git a/addons/point_of_sale/static/src/js/devices.js b/addons/point_of_sale/static/src/js/devices.js index bc697e96aca..67fde81136a 100644 --- a/addons/point_of_sale/static/src/js/devices.js +++ b/addons/point_of_sale/static/src/js/devices.js @@ -450,7 +450,7 @@ function openerp_pos_devices(instance,module){ //module is instance.point_of_sal // it will check its validity then return an object containing various // information about the ean. // most importantly : - // - ean : the ean + // - code : the ean // - type : the type of the ean: // 'price' | 'weight' | 'unit' | 'cashier' | 'client' | 'discount' | 'error' // @@ -460,13 +460,16 @@ function openerp_pos_devices(instance,module){ //module is instance.point_of_sal // - unit : if the encoded value has a unit, it will be put there. // not to be confused with the 'unit' type, which represent an unit of a // unique product + // - base_code : the ean code with all the encoding parts set to zero; the one put on + // the product in the backend parse_ean: function(ean){ var parse_result = { - type:'unknown', // + encoding: 'ean13', + type:'unknown', prefix:'', - ean:ean, - base_ean: ean, + code:ean, + base_code: ean, id:'', value: 0, unit: 'none', @@ -487,13 +490,13 @@ function openerp_pos_devices(instance,module){ //module is instance.point_of_sal parse_result.type = 'error'; } else if( match_prefix(this.price_prefix_set,'price')){ parse_result.id = ean.substring(0,7); - parse_result.base_ean = this.sanitize_ean(ean.substring(0,7)); + parse_result.base_code = this.sanitize_ean(ean.substring(0,7)); parse_result.value = Number(ean.substring(7,12))/100.0; parse_result.unit = 'euro'; } else if( match_prefix(this.weight_prefix_set,'weight')){ parse_result.id = ean.substring(0,7); parse_result.value = Number(ean.substring(7,12))/1000.0; - parse_result.base_ean = this.sanitize_ean(ean.substring(0,7)); + parse_result.base_code = this.sanitize_ean(ean.substring(0,7)); parse_result.unit = 'Kg'; } else if( match_prefix(this.client_prefix_set,'client')){ parse_result.id = ean.substring(0,7); @@ -502,7 +505,7 @@ function openerp_pos_devices(instance,module){ //module is instance.point_of_sal parse_result.id = ean.substring(0,7); } else if( match_prefix(this.discount_prefix_set,'discount')){ parse_result.id = ean.substring(0,7); - parse_result.base_ean = this.sanitize_ean(ean.substring(0,7)); + parse_result.base_code = this.sanitize_ean(ean.substring(0,7)); parse_result.value = Number(ean.substring(7,12))/100.0; parse_result.unit = '%'; } else { @@ -512,9 +515,18 @@ function openerp_pos_devices(instance,module){ //module is instance.point_of_sal } return parse_result; }, - - on_ean: function(ean){ - var parse_result = this.parse_ean(ean); + + scan: function(type,code){ + if (type === 'ean13'){ + var parse_result = this.parse_ean(code); + }else if(type === 'reference'){ + var parse_result = { + encoding: 'reference', + type: 'unit', + code: code, + prefix: '', + }; + } if (parse_result.type === 'error') { //most likely a checksum error, raise warning console.warn('WARNING: barcode checksum error:',parse_result); @@ -522,7 +534,6 @@ function openerp_pos_devices(instance,module){ //module is instance.point_of_sal if(this.action_callback['product']){ this.action_callback['product'](parse_result); } - //this.trigger("codebar",parse_result ); }else{ if(this.action_callback[parse_result.type]){ this.action_callback[parse_result.type](parse_result); @@ -530,49 +541,63 @@ function openerp_pos_devices(instance,module){ //module is instance.point_of_sal } }, + on_reference: function(code){ + if(this.action_callback['reference']){ + this.action_callback['reference'](code); + } + }, + // starts catching keyboard events and tries to interpret codebar // calling the callbacks when needed. connect: function(){ + var self = this; - var codeNumbers = []; - var timeStamp = 0; - var lastTimeStamp = 0; + var code = ""; + var timeStamp = 0; + var onlynumbers = true; + var timeout = null; - // The barcode readers acts as a keyboard, we catch all keyup events and try to find a - // barcode sequence in the typed keys, then act accordingly. - $('body').delegate('','keypress', function (e){ - //console.log('keyup:'+String.fromCharCode(e.keyCode)+' '+e.keyCode,e); - //We only care about numbers - if (e.keyCode >= 48 && e.keyCode < 58){ + this.handler = function(e){ - // The barcode reader sends keystrokes with a specific interval. - // We look if the typed keys fit in the interval. - if (codeNumbers.length === 0) { - timeStamp = new Date().getTime(); - } else { - if (lastTimeStamp + 30 < new Date().getTime()) { - // not a barcode reader - codeNumbers = []; - timeStamp = new Date().getTime(); - } - } - codeNumbers.push(e.keyCode - 48); - lastTimeStamp = new Date().getTime(); - if (codeNumbers.length === 13) { - //We have found what seems to be a valid codebar - self.on_ean(codeNumbers.join('')); - codeNumbers = []; - } - } else { - // NaN - codeNumbers = []; + if(e.which === 13){ //ignore returns + return; } - }); + + if(timeStamp + 50 < new Date().getTime()){ + code = ""; + onlynumbers = true; + } + + timeStamp = new Date().getTime(); + clearTimeout(timeout); + + if( e.which < 48 || e.which >= 58 ){ // not a number + onlynumbers = false; + } + + code += String.fromCharCode(e.which); + + // we wait for a while after the last input to be sure that we are not mistakingly + // returning a code which is a prefix of a bigger one : + // Internal Ref 5449 vs EAN13 5449000... + + timeout = setTimeout(function(){ + if(code.length === 13 && onlynumbers){ + self.scan('ean13',code); + }else if(code.length >= 3 && self.pos.db.get_product_by_reference(code)){ + self.scan('reference',code); + } + code = ""; + onlynumbers = true; + },100); + }; + + $('body').on('keypress', this.handler); }, // stops catching keyboard events disconnect: function(){ - $('body').undelegate('', 'keyup') + $('body').off('keypress', this.handler) }, }); diff --git a/addons/point_of_sale/static/src/js/models.js b/addons/point_of_sale/static/src/js/models.js index 6d5fd1fc422..e47101ce27d 100644 --- a/addons/point_of_sale/static/src/js/models.js +++ b/addons/point_of_sale/static/src/js/models.js @@ -52,6 +52,7 @@ function openerp_pos_models(instance, module){ //module is instance.point_of_sal 'pos_config': null, 'units': null, 'units_by_id': null, + 'pricelist': null, 'selectedOrder': null, }); @@ -113,10 +114,6 @@ function openerp_pos_models(instance, module){ //module is instance.point_of_sal }).then(function(company_partners){ self.get('company').contact_address = company_partners[0].contact_address; - return self.fetch('res.currency',['symbol','position','rounding','accuracy'],[['id','=',self.get('company').currency_id[0]]]); - }).then(function(currencies){ - self.set('currency',currencies[0]); - return self.fetch('product.uom', null, null); }).then(function(units){ self.set('units',units); @@ -172,6 +169,14 @@ function openerp_pos_models(instance, module){ //module is instance.point_of_sal }).then(function(shops){ self.set('shop',shops[0]); + return self.fetch('product.pricelist',['currency_id'],[['id','=',self.get('pos_config').pricelist_id[0]]]); + }).then(function(pricelists){ + self.set('pricelist',pricelists[0]); + + return self.fetch('res.currency',['symbol','position','rounding','accuracy'],[['id','=',self.get('pricelist').currency_id[0]]]); + }).then(function(currencies){ + self.set('currency',currencies[0]); + return self.fetch('product.packaging',['ean','product_id']); }).then(function(packagings){ self.db.add_packagings(packagings); @@ -185,7 +190,7 @@ function openerp_pos_models(instance, module){ //module is instance.point_of_sal ['name', 'list_price','price','pos_categ_id', 'taxes_id', 'ean13', 'default_code', 'to_weight', 'uom_id', 'uos_id', 'uos_coeff', 'mes_type', 'description_sale', 'description'], [['sale_ok','=',true],['available_in_pos','=',true]], - {pricelist: self.get('pos_config').pricelist_id[0]} // context for price + {pricelist: self.get('pricelist').id} // context for price ); }).then(function(products){ self.db.add_products(products); @@ -423,19 +428,23 @@ function openerp_pos_models(instance, module){ //module is instance.point_of_sal return tried_all; }, - scan_product: function(parsed_ean){ + scan_product: function(parsed_code){ var self = this; - var product = this.db.get_product_by_ean13(parsed_ean.base_ean); var selectedOrder = this.get('selectedOrder'); + if(parsed_code.encoding === 'ean13'){ + var product = this.db.get_product_by_ean13(parsed_code.base_code); + }else if(parsed_code.encoding === 'reference'){ + var product = this.db.get_product_by_reference(parsed_code.code); + } if(!product){ return false; } - if(parsed_ean.type === 'price'){ - selectedOrder.addProduct(new module.Product(product), {price:parsed_ean.value}); - }else if(parsed_ean.type === 'weight'){ - selectedOrder.addProduct(new module.Product(product), {quantity:parsed_ean.value, merge:false}); + if(parsed_code.type === 'price'){ + selectedOrder.addProduct(new module.Product(product), {price:parsed_code.value}); + }else if(parsed_code.type === 'weight'){ + selectedOrder.addProduct(new module.Product(product), {quantity:parsed_code.value, merge:false}); }else{ selectedOrder.addProduct(new module.Product(product)); } diff --git a/addons/point_of_sale/static/src/js/screens.js b/addons/point_of_sale/static/src/js/screens.js index a5017d517b7..77a542ff93c 100644 --- a/addons/point_of_sale/static/src/js/screens.js +++ b/addons/point_of_sale/static/src/js/screens.js @@ -160,29 +160,29 @@ function openerp_pos_screens(instance, module){ //module is instance.point_of_sa // what happens when a product is scanned : // it will add the product to the order and go to barcode_product_screen. Or show barcode_product_error_popup if // there's an error. - barcode_product_action: function(ean){ + barcode_product_action: function(code){ var self = this; - if(self.pos.scan_product(ean)){ - self.pos.proxy.scan_item_success(ean); + if(self.pos.scan_product(code)){ + self.pos.proxy.scan_item_success(code); if(self.barcode_product_screen){ self.pos_widget.screen_selector.set_current_screen(self.barcode_product_screen); } }else{ - self.pos.proxy.scan_item_error_unrecognized(ean); + self.pos.proxy.scan_item_error_unrecognized(code); if(self.barcode_product_error_popup && self.pos_widget.screen_selector.get_user_mode() !== 'cashier'){ self.pos_widget.screen_selector.show_popup(self.barcode_product_error_popup); } } }, - + // what happens when a cashier id barcode is scanned. // the default behavior is the following : // - if there's a user with a matching ean, put it as the active 'cashier', go to cashier mode, and return true // - else : do nothing and return false. You probably want to extend this to show and appropriate error popup... - barcode_cashier_action: function(ean){ + barcode_cashier_action: function(code){ var users = this.pos.get('user_list'); for(var i = 0, len = users.length; i < len; i++){ - if(users[i].ean13 === ean.ean){ + if(users[i].ean13 === code.code){ this.pos.set('cashier',users[i]); this.pos_widget.username.refresh(); this.pos.proxy.cashier_mode_activated(); @@ -190,7 +190,7 @@ function openerp_pos_screens(instance, module){ //module is instance.point_of_sa return true; } } - this.pos.proxy.scan_item_error_unrecognized(ean); + this.pos.proxy.scan_item_error_unrecognized(code); return false; }, @@ -198,28 +198,28 @@ function openerp_pos_screens(instance, module){ //module is instance.point_of_sa // the default behavior is the following : // - if there's a user with a matching ean, put it as the active 'client' and return true // - else : return false. - barcode_client_action: function(ean){ + barcode_client_action: function(code){ var partners = this.pos.get('partner_list'); for(var i = 0, len = partners.length; i < len; i++){ - if(partners[i].ean13 === ean.ean){ + if(partners[i].ean13 === code.code){ this.pos.get('selectedOrder').set_client(partners[i]); this.pos_widget.username.refresh(); - this.pos.proxy.scan_item_success(ean); + this.pos.proxy.scan_item_success(code); return true; } } - this.pos.proxy.scan_item_error_unrecognized(ean); + this.pos.proxy.scan_item_error_unrecognized(code); return false; //TODO start the transaction }, // what happens when a discount barcode is scanned : the default behavior // is to set the discount on the last order. - barcode_discount_action: function(ean){ - this.pos.proxy.scan_item_success(ean); + barcode_discount_action: function(code){ + this.pos.proxy.scan_item_success(code); var last_orderline = this.pos.get('selectedOrder').getLastOrderline(); if(last_orderline){ - last_orderline.set_discount(ean.value) + last_orderline.set_discount(code.value) } }, @@ -292,10 +292,10 @@ function openerp_pos_screens(instance, module){ //module is instance.point_of_sa this.pos_widget.username.set_user_mode(this.pos_widget.screen_selector.get_user_mode()); this.pos.barcode_reader.set_action_callback({ - 'cashier': self.barcode_cashier_action ? function(ean){ self.barcode_cashier_action(ean); } : undefined , - 'product': self.barcode_product_action ? function(ean){ self.barcode_product_action(ean); } : undefined , - 'client' : self.barcode_client_action ? function(ean){ self.barcode_client_action(ean); } : undefined , - 'discount': self.barcode_discount_action ? function(ean){ self.barcode_discount_action(ean); } : undefined, + 'cashier': self.barcode_cashier_action ? function(code){ self.barcode_cashier_action(code); } : undefined , + 'product': self.barcode_product_action ? function(code){ self.barcode_product_action(code); } : undefined , + 'client' : self.barcode_client_action ? function(code){ self.barcode_client_action(code); } : undefined , + 'discount': self.barcode_discount_action ? function(code){ self.barcode_discount_action(code); } : undefined, }); }, @@ -405,7 +405,7 @@ function openerp_pos_screens(instance, module){ //module is instance.point_of_sa this.pos.barcode_reader.save_callbacks(); this.pos.barcode_reader.reset_action_callbacks(); this.pos.barcode_reader.set_action_callback({ - 'cashier': function(ean){ + 'cashier': function(code){ clearInterval(this.intervalID); self.pos.proxy.cashier_mode_activated(); self.pos_widget.screen_selector.set_user_mode('cashier'); @@ -683,14 +683,14 @@ function openerp_pos_screens(instance, module){ //module is instance.point_of_sa show_numpad: false, show_leftpane: false, - barcode_product_action: function(ean){ + barcode_product_action: function(code){ this.pos.proxy.transaction_start(); - this._super(ean); + this._super(code); }, - barcode_client_action: function(ean){ + barcode_client_action: function(code){ this.pos.proxy.transaction_start(); - this._super(ean); + this._super(code); $('.goodbye-message').addClass('oe_hidden'); this.pos_widget.screen_selector.show_popup('choose-receipt'); }, @@ -883,6 +883,11 @@ function openerp_pos_screens(instance, module){ //module is instance.point_of_sa label: _t('Back'), icon: '/point_of_sale/static/src/img/icons/png48/go-previous.png', click: function(){ + _.each(self.paymentlinewidgets, function(widget){ + if( widget.payment_line.get_amount() === 0 ){ + widget.payment_line.destroy(); + } + }); self.pos_widget.screen_selector.set_current_screen(self.back_screen); }, }); diff --git a/addons/point_of_sale/static/src/js/widget_keyboard.js b/addons/point_of_sale/static/src/js/widget_keyboard.js index 05ccdd78ca6..22245b31227 100644 --- a/addons/point_of_sale/static/src/js/widget_keyboard.js +++ b/addons/point_of_sale/static/src/js/widget_keyboard.js @@ -43,10 +43,15 @@ function openerp_pos_keyboard(instance, module){ //module is instance.point_of_s // Write a character to the input zone writeCharacter: function(character){ - var $input = this.$target - $input[0].value += character; - $input.keydown(); - $input.keyup(); + var $input = this.$target; + if(character === '\n'){ + $input.trigger($.Event('keydown',{which:13})); + $input.trigger($.Event('keyup',{which:13})); + }else{ + $input[0].value += character; + $input.keydown(); + $input.keyup(); + } }, // Sends a 'return' character to the input zone. TODO diff --git a/addons/point_of_sale/static/src/js/widgets.js b/addons/point_of_sale/static/src/js/widgets.js index cfec71be68d..291c8bfdaae 100644 --- a/addons/point_of_sale/static/src/js/widgets.js +++ b/addons/point_of_sale/static/src/js/widgets.js @@ -516,7 +516,6 @@ function openerp_pos_widgets(instance, module){ //module is instance.point_of_sa var cat = self.pos.db.get_category_by_id(id); self.set_category(cat); self.renderElement(); - self.search_and_categories(cat); }); }); // breadcrumb click actions @@ -525,12 +524,13 @@ function openerp_pos_widgets(instance, module){ //module is instance.point_of_sa var category = self.pos.db.get_category_by_id(id); self.set_category(category); self.renderElement(); - self.search_and_categories(category); }); + + this.search_and_categories(); + if(this.pos.iface_vkeyboard && this.pos_widget.onscreen_keyboard){ this.pos_widget.onscreen_keyboard.connect(this.$('.searchbox input')); } - this.search_and_categories(); }, set_product_type: function(type){ // 'all' | 'weightable' @@ -542,7 +542,14 @@ function openerp_pos_widgets(instance, module){ //module is instance.point_of_sa reset_category: function(){ this.set_category(); this.renderElement(); - this.search_and_categories(); + }, + + // empties the content of the search box + clear_search: function(){ + var products = this.pos.db.get_product_by_category(this.category.id); + this.pos.get('products').reset(products); + this.$('.searchbox input').val('').focus(); + this.$('.search-clear').fadeOut(); }, // filters the products, and sets up the search callbacks @@ -554,12 +561,20 @@ function openerp_pos_widgets(instance, module){ //module is instance.point_of_sa self.pos.get('products').reset(products); // filter the products according to the search string - this.$('.searchbox input').keyup(function(){ + this.$('.searchbox input').keyup(function(event){ + console.log('event',event); query = $(this).val().toLowerCase(); if(query){ - var products = self.pos.db.search_product_in_category(self.category.id, query); - self.pos.get('products').reset(products); - self.$('.search-clear').fadeIn(); + if(event.which === 13){ + if( self.pos.get('products').size() === 1 ){ + self.pos.get('selectedOrder').addProduct(self.pos.get('products').at(0)); + self.clear_search(); + } + }else{ + var products = self.pos.db.search_product_in_category(self.category.id, query); + self.pos.get('products').reset(products); + self.$('.search-clear').fadeIn(); + } }else{ var products = self.pos.db.get_product_by_category(self.category.id); self.pos.get('products').reset(products); @@ -567,14 +582,9 @@ function openerp_pos_widgets(instance, module){ //module is instance.point_of_sa } }); - this.$('.searchbox input').click(function(){}); //Why ??? - //reset the search when clicking on reset this.$('.search-clear').click(function(){ - var products = self.pos.db.get_product_by_category(self.category.id); - self.pos.get('products').reset(products); - self.$('.searchbox input').val('').focus(); - self.$('.search-clear').fadeOut(); + self.clear_search(); }); }, }); @@ -668,7 +678,9 @@ function openerp_pos_widgets(instance, module){ //module is instance.point_of_sa var self = this; this._super(); if(this.action){ - this.$el.click(function(){ self.action(); }); + this.$el.click(function(){ + self.action(); + }); } }, show: function(){ this.$el.removeClass('oe_hidden'); }, @@ -732,12 +744,15 @@ function openerp_pos_widgets(instance, module){ //module is instance.point_of_sa this.$('.button.custom_ean').click(function(){ var ean = self.pos.barcode_reader.sanitize_ean(self.$('input.ean').val() || '0'); self.$('input.ean').val(ean); - self.pos.barcode_reader.on_ean(ean); + self.pos.barcode_reader.scan('ean13',ean); + }); + this.$('.button.reference').click(function(){ + self.pos.barcode_reader.scan('reference',self.$('input.ean').val()); }); _.each(this.eans, function(ean, name){ self.$('.button.'+name).click(function(){ self.$('input.ean').val(ean); - self.pos.barcode_reader.on_ean(ean); + self.pos.barcode_reader.scan('ean13',ean); }); }); _.each(this.events, function(name){ @@ -1082,15 +1097,29 @@ function openerp_pos_widgets(instance, module){ //module is instance.point_of_sa }, close: function() { var self = this; - return new instance.web.Model("ir.model.data").get_func("search_read")([['name', '=', 'action_client_pos_menu']], ['res_id']).pipe( - _.bind(function(res) { - return this.rpc('/web/action/load', {'action_id': res[0]['res_id']}).pipe(_.bind(function(result) { - var action = result; - action.context = _.extend(action.context || {}, {'cancel_action': {type: 'ir.actions.client', tag: 'reload'}}); - //self.destroy(); - this.do_action(action); - }, this)); - }, this)); + + function close(){ + return new instance.web.Model("ir.model.data").get_func("search_read")([['name', '=', 'action_client_pos_menu']], ['res_id']).pipe( + _.bind(function(res) { + return this.rpc('/web/action/load', {'action_id': res[0]['res_id']}).pipe(_.bind(function(result) { + var action = result; + action.context = _.extend(action.context || {}, {'cancel_action': {type: 'ir.actions.client', tag: 'reload'}}); + //self.destroy(); + this.do_action(action); + }, this)); + }, self)); + } + + var draft_order = _.find( self.pos.get('orders').models, function(order){ + return order.get('orderLines').length !== 0 && order.get('paymentLines').length === 0; + }); + if(draft_order){ + if (confirm(_t("Pending orders will be lost.\nAre you sure you want to leave this session?"))) { + return close(); + } + }else{ + return close(); + } }, destroy: function() { this.pos.destroy(); diff --git a/addons/point_of_sale/static/src/xml/pos.xml b/addons/point_of_sale/static/src/xml/pos.xml index 7456c29b9e5..d5f57e099f7 100644 --- a/addons/point_of_sale/static/src/xml/pos.xml +++ b/addons/point_of_sale/static/src/xml/pos.xml @@ -12,8 +12,8 @@
- - + +
    @@ -494,6 +494,7 @@
  1. 1.54€ Lemon
  2. Unknown Product
  3. Invalid Ean
  4. +
  5. Reference
  6. Hardware Status

    diff --git a/addons/point_of_sale/wizard/pos_session_opening.xml b/addons/point_of_sale/wizard/pos_session_opening.xml index a7dbe43c962..5aa3f8d4764 100644 --- a/addons/point_of_sale/wizard/pos_session_opening.xml +++ b/addons/point_of_sale/wizard/pos_session_opening.xml @@ -15,7 +15,7 @@ -