Compare commits
merge into: Myceliandre:12.0
Myceliandre:10.0
Myceliandre:11.0
Myceliandre:12.0
Myceliandre:12.0-vracoop-pos
Myceliandre:13.0
Myceliandre:7.0
Myceliandre:8.0
Myceliandre:9.0
pull from: Myceliandre:12.0-vracoop-pos
Myceliandre:10.0
Myceliandre:11.0
Myceliandre:12.0
Myceliandre:12.0-vracoop-pos
Myceliandre:13.0
Myceliandre:7.0
Myceliandre:8.0
Myceliandre:9.0
2 Commits
12.0
...
12.0-vraco
Author | SHA1 | Message | Date |
---|---|---|---|
|
7e5a259319 |
[REM] rem cert hash
|
4 years ago |
|
287e500f35 |
[NEW] initial merge between OCA and Vracoop
|
4 years ago |
121 changed files with 11707 additions and 0 deletions
-
24hw_customer_display/__init__.py
-
86hw_customer_display/__manifest__.py
-
24hw_customer_display/controllers/__init__.py
-
192hw_customer_display/controllers/main.py
-
14hw_customer_display/i18n/hw_customer_display.pot
-
80hw_customer_display/test-scripts/customer-display-test.py
-
4hw_customer_display_currency/__init__.py
-
19hw_customer_display_currency/__manifest__.py
-
2hw_customer_display_currency/controllers/__init__.py
-
133hw_customer_display_currency/controllers/main.py
-
102hw_customer_display_currency/test-scripts/customer_display_currency_test.py
-
81pos_container/README.rst
-
2pos_container/__init__.py
-
36pos_container/__manifest__.py
-
20pos_container/data/product.xml
-
19pos_container/demo/demo.xml
-
384pos_container/i18n/fr.po
-
377pos_container/i18n/pos_container.pot
-
3pos_container/models/__init__.py
-
13pos_container/models/barcode.py
-
45pos_container/models/container.py
-
15pos_container/models/pos_order_line.py
-
2pos_container/readme/CONTRIBUTORS.rst
-
5pos_container/readme/DESCRIPTION.rst
-
2pos_container/readme/USAGE.rst
-
3pos_container/security/ir.model.access.csv
-
431pos_container/static/description/index.html
-
191pos_container/static/src/css/container.css
-
431pos_container/static/src/js/container.js
-
619pos_container/static/src/js/models_and_db.js
-
244pos_container/static/src/js/tests.js
-
442pos_container/static/src/xml/pos.xml
-
17pos_container/templates/templates.xml
-
1pos_container/tests/__init__.py
-
14pos_container/tests/test_pos_container.py
-
43pos_container/views/container.xml
-
3pos_customer_display_currency/__init__.py
-
33pos_customer_display_currency/__manifest__.py
-
3pos_customer_display_currency/models/__init__.py
-
30pos_customer_display_currency/models/pos_customer_display_currency.py
-
310pos_customer_display_currency/static/src/js/pos_customer_display_currency.js
-
10pos_customer_display_currency/templates/templates.xml
-
17pos_customer_display_currency/views/pos_config_view.xml
-
105pos_loyalty/README.rst
-
3pos_loyalty/__init__.py
-
36pos_loyalty/__manifest__.py
-
8pos_loyalty/demo/templates.xml
-
523pos_loyalty/i18n/es.po
-
504pos_loyalty/i18n/fr.po
-
498pos_loyalty/i18n/hr_HR.po
-
497pos_loyalty/i18n/it.po
-
498pos_loyalty/i18n/nl_NL.po
-
483pos_loyalty/i18n/pos_loyalty.pot
-
9pos_loyalty/models/__init__.py
-
30pos_loyalty/models/loyalty_program.py
-
73pos_loyalty/models/loyalty_reward.py
-
34pos_loyalty/models/loyalty_rule.py
-
14pos_loyalty/models/pos_config.py
-
30pos_loyalty/models/pos_order.py
-
20pos_loyalty/models/pos_order_line.py
-
13pos_loyalty/models/res_partner.py
-
4pos_loyalty/readme/CONFIGURE.rst
-
3pos_loyalty/readme/CONTRIBUTORS.rst
-
6pos_loyalty/readme/DESCRIPTION.rst
-
11pos_loyalty/readme/USAGE.rst
-
7pos_loyalty/security/ir.model.access.csv
-
BINpos_loyalty/static/description/icon.png
-
449pos_loyalty/static/description/index.html
-
21pos_loyalty/static/src/css/pos.css
-
477pos_loyalty/static/src/js/pos.js
-
170pos_loyalty/static/src/js/tests.js
-
85pos_loyalty/static/src/xml/pos.xml
-
2pos_loyalty/tests/__init__.py
-
74pos_loyalty/tests/test_pos_loyalty.py
-
83pos_loyalty/views/loyalty_program_view.xml
-
37pos_loyalty/views/loyalty_reward_view.xml
-
31pos_loyalty/views/loyalty_rule_view.xml
-
23pos_loyalty/views/pos_config_view.xml
-
15pos_loyalty/views/pos_order_view.xml
-
18pos_loyalty/views/res_partner_view.xml
-
9pos_loyalty/views/templates.xml
-
86pos_mail_receipt/README.rst
-
1pos_mail_receipt/__init__.py
-
14pos_mail_receipt/__manifest__.py
-
19pos_mail_receipt/data/email.xml
-
131pos_mail_receipt/i18n/fr.po
-
122pos_mail_receipt/i18n/pos_mail_receipt.pot
-
1pos_mail_receipt/models/__init__.py
-
86pos_mail_receipt/models/pos_order.py
-
3pos_mail_receipt/readme/CONTRIBUTORS.rst
-
5pos_mail_receipt/readme/DESCRIPTION.rst
-
3pos_mail_receipt/readme/USAGE.rst
-
BINpos_mail_receipt/static/description/icon.png
-
434pos_mail_receipt/static/description/index.html
-
3pos_mail_receipt/static/src/css/pos.css
-
129pos_mail_receipt/static/src/css/print.css
-
102pos_mail_receipt/static/src/js/screens.js
-
13pos_mail_receipt/static/src/xml/pos.xml
-
20pos_mail_receipt/templates/assets.xml
-
1pos_mail_receipt/tests/__init__.py
@ -0,0 +1,24 @@ |
|||||
|
# -*- coding: utf-8 -*- |
||||
|
############################################################################## |
||||
|
# |
||||
|
# Hardware Customer Display module for Odoo |
||||
|
# Copyright (C) 2014 Akretion (http://www.akretion.com) |
||||
|
# @author Alexis de Lattre <alexis.delattre@akretion.com> |
||||
|
# |
||||
|
# 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 . import controllers |
@ -0,0 +1,86 @@ |
|||||
|
# -*- encoding: utf-8 -*- |
||||
|
############################################################################## |
||||
|
# |
||||
|
# Hardware Customer Display module for Odoo |
||||
|
# Copyright (C) 2014 Akretion (http://www.akretion.com) |
||||
|
# @author Alexis de Lattre <alexis.delattre@akretion.com> |
||||
|
# |
||||
|
# 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/>. |
||||
|
# |
||||
|
############################################################################## |
||||
|
|
||||
|
|
||||
|
{ |
||||
|
'name': 'Hardware Customer Display', |
||||
|
'version': '12.0.0.1.0', |
||||
|
'category': 'Hardware Drivers', |
||||
|
'license': 'AGPL-3', |
||||
|
'summary': 'Adds support for Customer Display in the Point of Sale', |
||||
|
'description': """ |
||||
|
Hardware Customer Display |
||||
|
========================= |
||||
|
|
||||
|
This module adds support for Customer Display in the Point of Sale. |
||||
|
This module is designed to be installed on the *POSbox* (i.e. the |
||||
|
proxy on which the USB devices are connected) and not on the main |
||||
|
Odoo server. On the main Odoo server, you should install the module |
||||
|
*pos_customer_display*. |
||||
|
|
||||
|
The configuration of the hardware is done in the configuration file of |
||||
|
the Odoo server of the POSbox. You should add the following entries in |
||||
|
the configuration file: |
||||
|
|
||||
|
* customer_display_device_name (default = /dev/ttyUSB0) |
||||
|
* customer_display_device_rate (default = 9600) |
||||
|
* customer_display_device_timeout (default = 2 seconds) |
||||
|
|
||||
|
The number of cols of the Customer Display (usually 20) should be |
||||
|
configured on the main Odoo server, in the menu Point of Sale > |
||||
|
Configuration > Point of Sales. The number of rows is supposed to be 2. |
||||
|
|
||||
|
It should support most serial and USB-serial LCD displays out-of-the-box |
||||
|
or with inheritance of a few functions. |
||||
|
|
||||
|
It has been tested with: |
||||
|
|
||||
|
* Bixolon BCD-1100 (Datasheet : |
||||
|
http://www.bixolon.com/html/en/product/product_detail.xhtml?prod_id=61) |
||||
|
* Bixolon BCD-1000 |
||||
|
|
||||
|
To setup the BCD-1100 on Linux, you will find some technical instructions |
||||
|
on this page: |
||||
|
http://techtuxwords.blogspot.fr/2012/12/linux-and-bixolon-bcd-1100.html |
||||
|
|
||||
|
If you have a kernel >= 3.12, you should also read this: |
||||
|
http://www.leniwiec.org/en/2014/06/25/ubuntu-14-04lts-how-to-pass-id-ven |
||||
|
dor-and-id-product-to-ftdi_sio-driver/ |
||||
|
|
||||
|
This module has been developped during a POS code sprint at Akretion |
||||
|
France from July 7th to July 10th 2014. This module is part of the POS |
||||
|
project of the Odoo Community Association http://odoo-community.org/. |
||||
|
You are invited to become a member and/or get involved in the |
||||
|
Association ! |
||||
|
|
||||
|
This module has been written by Alexis de Lattre from Akretion |
||||
|
<alexis.delattre@akretion.com>. |
||||
|
""", |
||||
|
'author': "Akretion,Odoo Community Association (OCA)", |
||||
|
'website': 'http://www.akretion.com', |
||||
|
'depends': ['hw_proxy'], |
||||
|
'external_dependencies': { |
||||
|
'python': ['serial', 'unidecode'], |
||||
|
}, |
||||
|
'data': [], |
||||
|
'installable':'False' |
||||
|
} |
@ -0,0 +1,24 @@ |
|||||
|
# -*- encoding: utf-8 -*- |
||||
|
############################################################################## |
||||
|
# |
||||
|
# Hardware Customer Display module for Odoo |
||||
|
# Copyright (C) 2014 Akretion (http://www.akretion.com) |
||||
|
# @author Alexis de Lattre <alexis.delattre@akretion.com> |
||||
|
# |
||||
|
# 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 . import main |
@ -0,0 +1,192 @@ |
|||||
|
# -*- encoding: utf-8 -*- |
||||
|
############################################################################## |
||||
|
# |
||||
|
# Hardware Customer Display module for Odoo |
||||
|
# Copyright (C) 2014 Akretion (http://www.akretion.com) |
||||
|
# @author Alexis de Lattre <alexis.delattre@akretion.com> |
||||
|
# |
||||
|
# 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 logging |
||||
|
import json as simplejson |
||||
|
import time |
||||
|
from threading import Thread, Lock |
||||
|
from queue import Queue |
||||
|
import odoo.addons.hw_proxy.controllers.main as hw_proxy |
||||
|
from odoo import http |
||||
|
from odoo.tools.config import config |
||||
|
|
||||
|
logger = logging.getLogger(__name__) |
||||
|
|
||||
|
CLEAR_DISPLAY = b'\x0C' |
||||
|
MOVE_CURSOR_TO = b'\x1B\x6C' |
||||
|
CURSOR_OFF = b'\x1F\x43\x00' |
||||
|
|
||||
|
try: |
||||
|
from serial import Serial |
||||
|
from unidecode import unidecode |
||||
|
except (ImportError, IOError) as err: |
||||
|
logger.debug(err) |
||||
|
|
||||
|
|
||||
|
class CustomerDisplayDriver(Thread): |
||||
|
def __init__(self): |
||||
|
Thread.__init__(self) |
||||
|
self.queue = Queue() |
||||
|
self.lock = Lock() |
||||
|
self.status = {'status': 'connecting', 'messages': []} |
||||
|
self.device_name = config.get( |
||||
|
'customer_display_device_name', '/dev/ttyUSB0') |
||||
|
self.device_rate = int(config.get( |
||||
|
'customer_display_device_rate', 9600)) |
||||
|
self.device_timeout = int(config.get( |
||||
|
'customer_display_device_timeout', 2)) |
||||
|
self.serial = False |
||||
|
|
||||
|
def get_status(self): |
||||
|
self.push_task('status') |
||||
|
return self.status |
||||
|
|
||||
|
def set_status(self, status, message=None): |
||||
|
if status == self.status['status']: |
||||
|
if message is not None and message != self.status['messages'][-1]: |
||||
|
self.status['messages'].append(message) |
||||
|
else: |
||||
|
self.status['status'] = status |
||||
|
if message: |
||||
|
self.status['messages'] = [message] |
||||
|
else: |
||||
|
self.status['messages'] = [] |
||||
|
|
||||
|
if status == 'error' and message: |
||||
|
logger.error('Display Error: ' + message) |
||||
|
elif status == 'disconnected' and message: |
||||
|
logger.warning('Disconnected Display: ' + message) |
||||
|
|
||||
|
def lockedstart(self): |
||||
|
with self.lock: |
||||
|
if not self.isAlive(): |
||||
|
self.daemon = True |
||||
|
self.start() |
||||
|
|
||||
|
def push_task(self, task, data=None): |
||||
|
self.lockedstart() |
||||
|
self.queue.put((time.time(), task, data)) |
||||
|
|
||||
|
def move_cursor(self, col, row): |
||||
|
# Bixolon spec : 11. "Move Cursor to Specified Position" |
||||
|
position = MOVE_CURSOR_TO + chr(col).encode('ascii') + chr(row).encode('ascii') |
||||
|
self.cmd_serial_write(position) |
||||
|
|
||||
|
def display_text(self, lines): |
||||
|
logger.debug( |
||||
|
"Preparing to send the following lines to LCD: %s" % lines) |
||||
|
# We don't check the number of rows/cols here, because it has already |
||||
|
# been checked in the POS client in the JS code |
||||
|
for row, line in enumerate(lines, start=1): |
||||
|
self.move_cursor(1, row) |
||||
|
self.serial_write(unidecode(line).encode('ascii')) |
||||
|
|
||||
|
def setup_customer_display(self): |
||||
|
"""Set LCD cursor to off |
||||
|
If your LCD has different setup instruction(s), you should |
||||
|
inherit this function""" |
||||
|
# Bixolon spec : 35. "Set Cursor On/Off" |
||||
|
self.cmd_serial_write(CURSOR_OFF) |
||||
|
logger.debug('LCD cursor set to off') |
||||
|
|
||||
|
def clear_customer_display(self): |
||||
|
"""If your LCD has different clearing instruction, you should inherit |
||||
|
this function""" |
||||
|
# Bixolon spec : 12. "Clear Display Screen and Clear String Mode" |
||||
|
self.cmd_serial_write(CLEAR_DISPLAY) |
||||
|
logger.debug('Customer display cleared') |
||||
|
|
||||
|
def cmd_serial_write(self, command): |
||||
|
"""If your LCD requires a prefix and/or suffix on all commands, |
||||
|
you should inherit this function""" |
||||
|
assert isinstance(command, bytes), 'command must be a bytes string' |
||||
|
self.serial_write(command) |
||||
|
|
||||
|
def serial_write(self, text): |
||||
|
assert isinstance(text, bytes), 'text must be a bytes string' |
||||
|
self.serial.write(text) |
||||
|
|
||||
|
def send_text_customer_display(self, text_to_display): |
||||
|
"""This function sends the data to the serial/usb port. |
||||
|
We open and close the serial connection on every message display. |
||||
|
Why ? |
||||
|
1. Because it is not a problem for the customer display |
||||
|
2. Because it is not a problem for performance, according to my tests |
||||
|
3. Because it allows recovery on errors : you can unplug/replug the |
||||
|
customer display and it will work again on the next message without |
||||
|
problem |
||||
|
""" |
||||
|
lines = simplejson.loads(text_to_display) |
||||
|
assert isinstance(lines, list), 'lines_list should be a list' |
||||
|
try: |
||||
|
logger.debug( |
||||
|
'Opening serial port %s for customer display with baudrate %d' |
||||
|
% (self.device_name, self.device_rate)) |
||||
|
self.serial = Serial( |
||||
|
self.device_name, self.device_rate, |
||||
|
timeout=self.device_timeout) |
||||
|
logger.debug('serial.is_open = %s' % self.serial.isOpen()) |
||||
|
self.setup_customer_display() |
||||
|
self.clear_customer_display() |
||||
|
self.display_text(lines) |
||||
|
except Exception as e: |
||||
|
logger.error('Exception in serial connection: %s' % str(e)) |
||||
|
finally: |
||||
|
if self.serial: |
||||
|
logger.debug('Closing serial port for customer display') |
||||
|
self.serial.close() |
||||
|
|
||||
|
def run(self): |
||||
|
while True: |
||||
|
try: |
||||
|
timestamp, task, data = self.queue.get(True) |
||||
|
if task == 'display': |
||||
|
self.send_text_customer_display(data) |
||||
|
elif task == 'status': |
||||
|
serial = Serial( |
||||
|
self.device_name, self.device_rate, |
||||
|
timeout=self.device_timeout) |
||||
|
if serial.isOpen(): |
||||
|
self.set_status( |
||||
|
'connected', |
||||
|
'Connected to %s' % self.device_name |
||||
|
) |
||||
|
self.serial = serial |
||||
|
except Exception as e: |
||||
|
self.set_status('error', str(e)) |
||||
|
|
||||
|
|
||||
|
driver = CustomerDisplayDriver() |
||||
|
|
||||
|
hw_proxy.drivers['customer_display'] = driver |
||||
|
|
||||
|
|
||||
|
class CustomerDisplayProxy(hw_proxy.Proxy): |
||||
|
@http.route( |
||||
|
'/hw_proxy/send_text_customer_display', type='json', auth='none', |
||||
|
cors='*') |
||||
|
def send_text_customer_display(self, text_to_display): |
||||
|
logger.debug( |
||||
|
'LCD: Call send_text_customer_display with text=%s', |
||||
|
text_to_display) |
||||
|
driver.push_task('display', text_to_display) |
@ -0,0 +1,14 @@ |
|||||
|
# Translation of Odoo Server. |
||||
|
# This file contains the translation of the following modules: |
||||
|
# |
||||
|
msgid "" |
||||
|
msgstr "" |
||||
|
"Project-Id-Version: Odoo Server 8.0\n" |
||||
|
"Report-Msgid-Bugs-To: \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" |
||||
|
|
@ -0,0 +1,80 @@ |
|||||
|
# -*- coding: utf-8 -*- |
||||
|
# Author : Alexis de Lattre <alexis.delattre@akretion.com> |
||||
|
# The licence is in the file __manifest__.py |
||||
|
# This is a test script, that you can use if you want to test/play |
||||
|
# with the customer display independantly from the Odoo server |
||||
|
# It has been tested with a Bixolon BCD-1100 |
||||
|
|
||||
|
import sys |
||||
|
import logging |
||||
|
import time |
||||
|
|
||||
|
_logger = logging.getLogger(__name__) |
||||
|
|
||||
|
try: |
||||
|
from serial import Serial |
||||
|
from unidecode import unidecode |
||||
|
except (ImportError, IOError) as err: |
||||
|
_logger.debug(err) |
||||
|
|
||||
|
DEVICE = '/dev/bixolon' |
||||
|
DEVICE_RATE = 9600 |
||||
|
DEVICE_COLS = 20 |
||||
|
|
||||
|
CLEAR_DISPLAY = b'\x0C' |
||||
|
MOVE_CURSOR_TO = b'\x1B\x6C' |
||||
|
CURSOR_OFF = b'\x1F\x43\x00' |
||||
|
|
||||
|
|
||||
|
def display_text(ser, line1, line2): |
||||
|
print(("set lines to the right length (%s)" % DEVICE_COLS)) |
||||
|
for line in [line1, line2]: |
||||
|
if len(line) < DEVICE_COLS: |
||||
|
line += ' ' * (DEVICE_COLS - len(line)) |
||||
|
elif len(line) > DEVICE_COLS: |
||||
|
line = line[0:DEVICE_COLS] |
||||
|
assert len(line) == DEVICE_COLS, 'Wrong length' |
||||
|
print("try to clear display") |
||||
|
ser.write(CLEAR_DISPLAY) |
||||
|
print("clear done") |
||||
|
print("try to position at start of 1st line") |
||||
|
l1 = MOVE_CURSOR_TO + chr(1).encode('ascii') + chr(1).encode('ascii') |
||||
|
ser.write(l1) |
||||
|
print("position done") |
||||
|
print("try to write 1st line") |
||||
|
ser.write(unidecode(line1).encode('ascii')) |
||||
|
print("write 1st line done") |
||||
|
time.sleep(1) |
||||
|
print("try to position at start of 2nd line") |
||||
|
l2 = MOVE_CURSOR_TO + chr(1).encode('ascii') + chr(2).encode('ascii') |
||||
|
ser.write(l2) |
||||
|
print("position done") |
||||
|
print("try to write 2nd line") |
||||
|
ser.write(unidecode(line2).encode('ascii')) |
||||
|
print("write done") |
||||
|
|
||||
|
|
||||
|
def open_close_display(line1, line2): |
||||
|
ser = False |
||||
|
try: |
||||
|
print("open serial port") |
||||
|
ser = Serial(DEVICE, DEVICE_RATE, timeout=2) |
||||
|
print(("serial port open =", ser.isOpen())) |
||||
|
print(("serial name =", ser.name)) |
||||
|
print("try to set cursor to off") |
||||
|
ser.write(CURSOR_OFF) |
||||
|
print("cursor set to off") |
||||
|
display_text(ser, line1, line2) |
||||
|
except Exception as e: |
||||
|
print(('EXCEPTION e={}'.format(e))) |
||||
|
sys.exit(1) |
||||
|
finally: |
||||
|
if ser: |
||||
|
print("close serial port") |
||||
|
ser.close() |
||||
|
|
||||
|
|
||||
|
if __name__ == '__main__': |
||||
|
line1 = 'Coop IT Easy' |
||||
|
line2 = 'Migration to 12.0' |
||||
|
open_close_display(line1, line2) |
@ -0,0 +1,4 @@ |
|||||
|
# -*- coding: utf-8 -*- |
||||
|
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). |
||||
|
|
||||
|
from . import controllers |
@ -0,0 +1,19 @@ |
|||||
|
# -*- coding: utf-8 -*- |
||||
|
# Copyright 2019 Coop IT Easy SCRLfs |
||||
|
# Vincent Van Rossem <vvrossem@gmail.com> |
||||
|
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).{ |
||||
|
{ |
||||
|
'name': "Currency Management Extension for the Hardware Customer Display ", |
||||
|
'version': '12.0.1.0.0', |
||||
|
'summary': """ |
||||
|
Adds currency management to the Hardware Customer Display""", |
||||
|
|
||||
|
"author": "Coop IT Easy SCRLfs, " |
||||
|
"Odoo Community Association (OCA)", |
||||
|
'license': "AGPL-3", |
||||
|
'website': "https://github.com/OCA/pos/", |
||||
|
'category': 'Hardware Drivers', |
||||
|
'depends': ['hw_customer_display'], |
||||
|
'data': [], |
||||
|
'installable': False, |
||||
|
} |
@ -0,0 +1,2 @@ |
|||||
|
# -*- coding: utf-8 -*- |
||||
|
from . import main |
@ -0,0 +1,133 @@ |
|||||
|
# -*- coding: utf-8 -*- |
||||
|
# Copyright 2019 Coop IT Easy SCRLfs |
||||
|
# Vincent Van Rossem <vvrossem@gmail.com> |
||||
|
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). |
||||
|
|
||||
|
import logging |
||||
|
import json as simplejson |
||||
|
|
||||
|
import odoo.addons.hw_proxy.controllers.main as hw_proxy |
||||
|
from odoo.addons.hw_customer_display.controllers.main import CustomerDisplayDriver |
||||
|
from odoo import http |
||||
|
|
||||
|
logger = logging.getLogger(__name__) |
||||
|
|
||||
|
SELECT_USER_DEFINED_CHAR = b'\x1B\x25\x01' |
||||
|
DEFINE_USER_DEFINED_CHAR = b'\x1B\x26\x01' |
||||
|
EURO_SYMBOL_DRAWING = b'\x05\x14\x3E\x55\x41\x22' |
||||
|
INIT_DISPLAY = b'\x1B\x40' |
||||
|
|
||||
|
|
||||
|
try: |
||||
|
from serial import Serial |
||||
|
from unidecode import unidecode |
||||
|
except (ImportError, IOError) as err: |
||||
|
logger.debug(err) |
||||
|
|
||||
|
|
||||
|
class CustomerDisplayCurrencyDriver(CustomerDisplayDriver): |
||||
|
def __init__(self): |
||||
|
super().__init__() |
||||
|
self.currency_char_code = None |
||||
|
self.currency_code = None |
||||
|
|
||||
|
def init_customer_display(self): |
||||
|
self.serial.write(INIT_DISPLAY) |
||||
|
logger.debug('Init display') |
||||
|
|
||||
|
def set_currency_code(self, currency_code): |
||||
|
self.currency_code = currency_code |
||||
|
|
||||
|
def set_currency_char_code(self, currency_char_code): |
||||
|
self.currency_char_code = currency_char_code.encode('ascii') |
||||
|
|
||||
|
def send_currency_data_customer_display(self, currency_data): |
||||
|
currency_data = simplejson.loads(currency_data) |
||||
|
self.set_currency_code(currency_data['currency_code']) |
||||
|
self.set_currency_char_code(currency_data['currency_char']) |
||||
|
|
||||
|
def draw_euro_symbol(self): |
||||
|
cmd = DEFINE_USER_DEFINED_CHAR + self.currency_char_code + self.currency_char_code + EURO_SYMBOL_DRAWING |
||||
|
self.serial_write(cmd) |
||||
|
self.serial_write(SELECT_USER_DEFINED_CHAR) |
||||
|
logger.debug('Draw euro symbol') |
||||
|
|
||||
|
def send_text_customer_display(self, text_to_display): |
||||
|
"""This function sends the data to the serial/usb port. |
||||
|
We open and close the serial connection on every message display. |
||||
|
Why ? |
||||
|
1. Because it is not a problem for the customer display |
||||
|
2. Because it is not a problem for performance, according to my tests |
||||
|
3. Because it allows recovery on errors : you can unplug/replug the |
||||
|
customer display and it will work again on the next message without |
||||
|
problem |
||||
|
""" |
||||
|
lines = simplejson.loads(text_to_display) |
||||
|
assert isinstance(lines, list), 'lines_list should be a list' |
||||
|
try: |
||||
|
logger.debug( |
||||
|
'Opening serial port %s for customer display with baudrate %d' |
||||
|
% (self.device_name, self.device_rate)) |
||||
|
self.serial = Serial( |
||||
|
self.device_name, self.device_rate, |
||||
|
timeout=self.device_timeout) |
||||
|
logger.debug('serial.is_open = %s' % self.serial.isOpen()) |
||||
|
|
||||
|
self.init_customer_display() |
||||
|
self.setup_customer_display() # set cursor off |
||||
|
|
||||
|
if self.currency_code == 'EUR': |
||||
|
self.draw_euro_symbol() |
||||
|
self.display_text(lines) |
||||
|
except Exception as e: |
||||
|
logger.error('Exception in serial connection: %s' % str(e)) |
||||
|
finally: |
||||
|
if self.serial: |
||||
|
logger.debug('Closing serial port for customer display') |
||||
|
self.serial.close() |
||||
|
|
||||
|
def run(self): |
||||
|
while True: |
||||
|
try: |
||||
|
timestamp, task, data = self.queue.get(True) |
||||
|
if task == 'display': |
||||
|
self.send_text_customer_display(data) |
||||
|
elif task == 'currency': |
||||
|
self.send_currency_data_customer_display(data) |
||||
|
elif task == 'status': |
||||
|
serial = Serial( |
||||
|
self.device_name, self.device_rate, |
||||
|
timeout=self.device_timeout) |
||||
|
if serial.isOpen(): |
||||
|
self.set_status( |
||||
|
'connected', |
||||
|
'Connected to %s' % self.device_name |
||||
|
) |
||||
|
self.serial = serial |
||||
|
except Exception as e: |
||||
|
self.set_status('error', str(e)) |
||||
|
|
||||
|
|
||||
|
driver = CustomerDisplayCurrencyDriver() |
||||
|
|
||||
|
hw_proxy.drivers['customer_display'] = driver |
||||
|
|
||||
|
|
||||
|
class CustomerDisplayCurrencyProxy(hw_proxy.Proxy): |
||||
|
@http.route( |
||||
|
'/hw_proxy/send_text_customer_display', type='json', auth='none', |
||||
|
cors='*') |
||||
|
def send_text_customer_display(self, text_to_display): |
||||
|
logger.debug( |
||||
|
'LCD: Call send_text_customer_display with text=%s', |
||||
|
text_to_display) |
||||
|
driver.push_task('display', text_to_display) |
||||
|
|
||||
|
@http.route( |
||||
|
'/hw_proxy/send_currency_data_customer_display', type='json', auth='none', |
||||
|
cors='*') |
||||
|
def send_currency_data_customer_display(self, currency_data): |
||||
|
logger.debug( |
||||
|
'LCD: Call send_currency_data_customer_display with json=%s', |
||||
|
currency_data) |
||||
|
driver.push_task('currency', currency_data) |
@ -0,0 +1,102 @@ |
|||||
|
# -*- coding: utf-8 -*- |
||||
|
# Copyright 2019 Coop IT Easy SCRLfs |
||||
|
# Vincent Van Rossem <vvrossem@gmail.com> |
||||
|
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). |
||||
|
|
||||
|
import sys |
||||
|
import logging |
||||
|
import time |
||||
|
|
||||
|
_logger = logging.getLogger(__name__) |
||||
|
|
||||
|
try: |
||||
|
from serial import Serial |
||||
|
from unidecode import unidecode |
||||
|
except (ImportError, IOError) as err: |
||||
|
_logger.debug(err) |
||||
|
|
||||
|
DEVICE = '/dev/bixolon' |
||||
|
DEVICE_RATE = 9600 |
||||
|
DEVICE_COLS = 20 |
||||
|
|
||||
|
# Bixolon BCD-1100 COMMANDS |
||||
|
INIT_DISPLAY = b'\x1B\x40' |
||||
|
MOVE_CURSOR_TO = b'\x1B\x6C' |
||||
|
SET_CURSOR_OFF = b'\x1F\x43\x00' |
||||
|
SELECT_USER_DEFINED_CHAR = b'\x1B\x25\x01' |
||||
|
DEFINE_USER_DEFINED_CHAR = b'\x1B\x26\x01' |
||||
|
EURO_SYMBOL_DRAWING = b'\x05\x14\x3E\x55\x41\x22' |
||||
|
|
||||
|
|
||||
|
def draw_euro_symbol(ser, char_code): |
||||
|
char_code = char_code.encode('ascii') |
||||
|
print('char_code encoded:', char_code) |
||||
|
cmd = DEFINE_USER_DEFINED_CHAR + char_code + char_code + EURO_SYMBOL_DRAWING |
||||
|
ser.write(cmd) |
||||
|
ser.write(SELECT_USER_DEFINED_CHAR) |
||||
|
|
||||
|
|
||||
|
def display_text(ser, line1, line2): |
||||
|
print("\nset lines to the right length (%s)" % DEVICE_COLS) |
||||
|
for line in [line1, line2]: |
||||
|
if len(line) < DEVICE_COLS: |
||||
|
line += ' ' * (DEVICE_COLS - len(line)) |
||||
|
elif len(line) > DEVICE_COLS: |
||||
|
line = line[0:DEVICE_COLS] |
||||
|
assert len(line) == DEVICE_COLS, 'Wrong length' |
||||
|
|
||||
|
print("\ntry to draw euro symbol") |
||||
|
draw_euro_symbol(ser, '~') |
||||
|
print('\tdraw euro symbol done') |
||||
|
|
||||
|
print("\ntry to position at start of 1st line") |
||||
|
l1 = MOVE_CURSOR_TO + chr(1).encode('ascii') + chr(1).encode('ascii') |
||||
|
ser.write(l1) |
||||
|
print("\tposition done") |
||||
|
|
||||
|
print("\ntry to write 1st line") |
||||
|
ser.write(unidecode(line1).encode('ascii')) |
||||
|
print("\twrite 1st line done") |
||||
|
|
||||
|
time.sleep(1) |
||||
|
|
||||
|
print("\ntry to position at start of 2nd line") |
||||
|
l2 = MOVE_CURSOR_TO + chr(1).encode('ascii') + chr(2).encode('ascii') |
||||
|
ser.write(l2) |
||||
|
print("\tposition done") |
||||
|
|
||||
|
print("\ntry to write 2nd line") |
||||
|
ser.write(unidecode(line2).encode('ascii')) |
||||
|
print("\twrite 2nd line done") |
||||
|
|
||||
|
|
||||
|
def open_close_display(line1, line2): |
||||
|
ser = False |
||||
|
try: |
||||
|
print("open serial port") |
||||
|
ser = Serial(DEVICE, DEVICE_RATE, timeout=2) |
||||
|
print("serial port open =", ser.isOpen()) |
||||
|
print("serial name =", ser.name) |
||||
|
|
||||
|
print("\ntry to (re)initialize display") |
||||
|
ser.write(INIT_DISPLAY) |
||||
|
print("\t(re)initialize display done") |
||||
|
|
||||
|
print("\ntry to set cursor to off") |
||||
|
ser.write(SET_CURSOR_OFF) |
||||
|
print("\tcursor set to off") |
||||
|
|
||||
|
display_text(ser, line1, line2) |
||||
|
except Exception as e: |
||||
|
print('EXCEPTION e={}'.format(e)) |
||||
|
sys.exit(1) |
||||
|
finally: |
||||
|
if ser: |
||||
|
print("\nclose serial port") |
||||
|
ser.close() |
||||
|
|
||||
|
|
||||
|
if __name__ == '__main__': |
||||
|
line1 = 'Coop IT Easy' |
||||
|
line2 = 'Draw € symbol: ~' |
||||
|
open_close_display(line1, line2) |
@ -0,0 +1,81 @@ |
|||||
|
============= |
||||
|
POS Container |
||||
|
============= |
||||
|
|
||||
|
.. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! |
||||
|
!! This file is generated by oca-gen-addon-readme !! |
||||
|
!! changes will be overwritten. !! |
||||
|
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! |
||||
|
|
||||
|
.. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png |
||||
|
:target: https://odoo-community.org/page/development-status |
||||
|
:alt: Beta |
||||
|
.. |badge2| image:: https://img.shields.io/badge/github-OCA%2Fpos-lightgray.png?logo=github |
||||
|
:target: https://github.com/OCA/pos/tree/12.0/pos_container |
||||
|
:alt: OCA/pos |
||||
|
.. |badge3| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png |
||||
|
:target: https://translation.odoo-community.org/projects/pos-12-0/pos-12-0-pos_container |
||||
|
:alt: Translate me on Weblate |
||||
|
.. |badge4| image:: https://img.shields.io/badge/runbot-Try%20me-875A7B.png |
||||
|
:target: https://runbot.odoo-community.org/runbot/184/12.0 |
||||
|
:alt: Try me on Runbot |
||||
|
|
||||
|
|badge1| |badge2| |badge3| |badge4| |
||||
|
|
||||
|
This module allows to handle use of reusable containers in POS, |
||||
|
this is useful to handle selling product in bulk without having to calculate |
||||
|
the tare of the container. |
||||
|
|
||||
|
Each container is identified by a barcode, the weight is stored in Odoo. |
||||
|
|
||||
|
**Table of contents** |
||||
|
|
||||
|
.. contents:: |
||||
|
:local: |
||||
|
|
||||
|
Usage |
||||
|
===== |
||||
|
|
||||
|
You have to create a Barcode Nomenclature to handle containers before using the |
||||
|
module. |
||||
|
|
||||
|
Bug Tracker |
||||
|
=========== |
||||
|
|
||||
|
Bugs are tracked on `GitHub Issues <https://github.com/OCA/pos/issues>`_. |
||||
|
In case of trouble, please check there if your issue has already been reported. |
||||
|
If you spotted it first, help us smashing it by providing a detailed and welcomed |
||||
|
`feedback <https://github.com/OCA/pos/issues/new?body=module:%20pos_container%0Aversion:%2012.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**>`_. |
||||
|
|
||||
|
Do not contact contributors directly about support or help with technical issues. |
||||
|
|
||||
|
Credits |
||||
|
======= |
||||
|
|
||||
|
Authors |
||||
|
~~~~~~~ |
||||
|
|
||||
|
* Coop IT Easy SCRLfs |
||||
|
|
||||
|
Contributors |
||||
|
~~~~~~~~~~~~ |
||||
|
|
||||
|
* Pierrick Brun <pierrick.brun@akretion.com> |
||||
|
* Robin Keunen <robin.keunen@coopiteasy.be> |
||||
|
|
||||
|
Maintainers |
||||
|
~~~~~~~~~~~ |
||||
|
|
||||
|
This module is maintained by the OCA. |
||||
|
|
||||
|
.. image:: https://odoo-community.org/logo.png |
||||
|
:alt: Odoo Community Association |
||||
|
:target: https://odoo-community.org |
||||
|
|
||||
|
OCA, or the Odoo Community Association, is a nonprofit organization whose |
||||
|
mission is to support the collaborative development of Odoo features and |
||||
|
promote its widespread use. |
||||
|
|
||||
|
This module is part of the `OCA/pos <https://github.com/OCA/pos/tree/12.0/pos_container>`_ project on GitHub. |
||||
|
|
||||
|
You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute. |
@ -0,0 +1,2 @@ |
|||||
|
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). |
||||
|
from . import models |
@ -0,0 +1,36 @@ |
|||||
|
# Copyright 2019 Coop IT Easy SCRLfs |
||||
|
# Robin Keunen <robin@coopiteasy.be> |
||||
|
# Pierrick Brun <pierrick.brun@akretion.com> |
||||
|
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).{ |
||||
|
{ |
||||
|
'name': "POS Container", |
||||
|
'version': '12.0.1.0.0', |
||||
|
|
||||
|
'summary': """ |
||||
|
Allows managing pre-weighted containers for bulk shop""", |
||||
|
|
||||
|
"author": "Coop IT Easy SCRLfs, " |
||||
|
"Odoo Community Association (OCA)", |
||||
|
'license': "AGPL-3", |
||||
|
'website': "https://github.com/OCA/pos/", |
||||
|
|
||||
|
'category': 'Point of Sale', |
||||
|
|
||||
|
'depends': ['point_of_sale'], |
||||
|
|
||||
|
'data': [ |
||||
|
'data/product.xml', |
||||
|
'views/container.xml', |
||||
|
'templates/templates.xml', |
||||
|
'security/ir.model.access.csv', |
||||
|
], |
||||
|
'demo': [ |
||||
|
'demo/demo.xml', |
||||
|
], |
||||
|
|
||||
|
'qweb': [ |
||||
|
'static/src/xml/pos.xml', |
||||
|
], |
||||
|
|
||||
|
'installable': True, |
||||
|
} |
@ -0,0 +1,20 @@ |
|||||
|
<odoo> |
||||
|
<record id="temporary_container_product" model="product.product"> |
||||
|
<field name="name">Container without product</field> |
||||
|
<!-- The barcode is used to find it from the POS --> |
||||
|
<field name="barcode">CONTAINER</field> |
||||
|
<field name="uom_id" ref="uom.product_uom_kgm"/> |
||||
|
<field name="uom_po_id" ref="uom.product_uom_kgm"/> |
||||
|
<field name="purchase_ok" eval="False"/> |
||||
|
<field name="description"> |
||||
|
This product is used to describe POS order lines having a container but no product yet |
||||
|
</field> |
||||
|
<field name="list_price">0</field> |
||||
|
<field name="available_in_pos" eval="True"/> |
||||
|
<field name="to_weight" eval="True"/> |
||||
|
<field name="active" eval="False"/> |
||||
|
</record> |
||||
|
<record id="temporary_container_product_product_template" model="product.template"> |
||||
|
<field name="active" eval="False"/> |
||||
|
</record> |
||||
|
</odoo> |
@ -0,0 +1,19 @@ |
|||||
|
<odoo> |
||||
|
<record id="container_1" model="pos.container"> |
||||
|
<field name="name">Container 1</field> |
||||
|
<field name="barcode">0498765456789</field> |
||||
|
<field name="weight">0.123</field> |
||||
|
</record> |
||||
|
|
||||
|
<record id="container_2" model="pos.container"> |
||||
|
<field name="name">Container 2</field> |
||||
|
<field name="barcode">0490987654356</field> |
||||
|
<field name="weight">0.234</field> |
||||
|
</record> |
||||
|
|
||||
|
<record id="container_3" model="pos.container"> |
||||
|
<field name="name">Container 3</field> |
||||
|
<field name="barcode">0490987654398</field> |
||||
|
<field name="weight">0.567</field> |
||||
|
</record> |
||||
|
</odoo> |
@ -0,0 +1,384 @@ |
|||||
|
# Translation of Odoo Server. |
||||
|
# This file contains the translation of the following modules: |
||||
|
# * pos_container |
||||
|
# |
||||
|
msgid "" |
||||
|
msgstr "" |
||||
|
"Project-Id-Version: Odoo Server 12.0\n" |
||||
|
"Report-Msgid-Bugs-To: \n" |
||||
|
"POT-Creation-Date: 2019-11-19 09:34+0000\n" |
||||
|
"PO-Revision-Date: 2019-11-19 10:42+0100\n" |
||||
|
"Last-Translator: <>\n" |
||||
|
"Language-Team: \n" |
||||
|
"MIME-Version: 1.0\n" |
||||
|
"Content-Type: text/plain; charset=UTF-8\n" |
||||
|
"Content-Transfer-Encoding: 8bit\n" |
||||
|
"Plural-Forms: \n" |
||||
|
"Language: fr\n" |
||||
|
"X-Generator: Poedit 2.2.4\n" |
||||
|
|
||||
|
#. module: pos_container |
||||
|
#: model:product.product,description:pos_container.temporary_container_product |
||||
|
#: model:product.template,description:pos_container.temporary_container_product_product_template |
||||
|
msgid "" |
||||
|
"\n" |
||||
|
" This product is used to describe POS order lines having a container but no product yet\n" |
||||
|
" " |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_container |
||||
|
#. openerp-web |
||||
|
#: code:addons/pos_container/static/src/xml/pos.xml:161 |
||||
|
#: code:addons/pos_container/static/src/xml/pos.xml:202 |
||||
|
#: code:addons/pos_container/static/src/xml/pos.xml:252 |
||||
|
#, python-format |
||||
|
msgid "% discount" |
||||
|
msgstr "% de réduction" |
||||
|
|
||||
|
#. module: pos_container |
||||
|
#. openerp-web |
||||
|
#: code:addons/pos_container/static/src/xml/pos.xml:127 |
||||
|
#, python-format |
||||
|
msgid "Add a container" |
||||
|
msgstr "Ajouter un contenant" |
||||
|
|
||||
|
#. module: pos_container |
||||
|
#: selection:barcode.rule,type:0 |
||||
|
msgid "Alias" |
||||
|
msgstr "Alias" |
||||
|
|
||||
|
#. module: pos_container |
||||
|
#. openerp-web |
||||
|
#: code:addons/pos_container/static/src/xml/pos.xml:184 |
||||
|
#: code:addons/pos_container/static/src/xml/pos.xml:318 |
||||
|
#, python-format |
||||
|
msgid "Automatic Weighing" |
||||
|
msgstr "Pesée automatique" |
||||
|
|
||||
|
#. module: pos_container |
||||
|
#. openerp-web |
||||
|
#: code:addons/pos_container/static/src/xml/pos.xml:124 |
||||
|
#, python-format |
||||
|
msgid "Back" |
||||
|
msgstr "Retour" |
||||
|
|
||||
|
#. module: pos_container |
||||
|
#. openerp-web |
||||
|
#: code:addons/pos_container/static/src/xml/pos.xml:48 |
||||
|
#: model:ir.model.fields,field_description:pos_container.field_pos_container__barcode |
||||
|
#, python-format |
||||
|
msgid "Barcode" |
||||
|
msgstr "Code Barre" |
||||
|
|
||||
|
#. module: pos_container |
||||
|
#: model:ir.model,name:pos_container.model_barcode_rule |
||||
|
msgid "Barcode Rule" |
||||
|
msgstr "Règle de code barre" |
||||
|
|
||||
|
#. module: pos_container |
||||
|
#. openerp-web |
||||
|
#: code:addons/pos_container/static/src/xml/pos.xml:22 |
||||
|
#, python-format |
||||
|
msgid "Cancel" |
||||
|
msgstr "Annuler" |
||||
|
|
||||
|
#. module: pos_container |
||||
|
#: selection:barcode.rule,type:0 |
||||
|
msgid "Cashier" |
||||
|
msgstr "Caissier" |
||||
|
|
||||
|
#. module: pos_container |
||||
|
#: selection:barcode.rule,type:0 |
||||
|
msgid "Client" |
||||
|
msgstr "Client" |
||||
|
|
||||
|
#. module: pos_container |
||||
|
#. openerp-web |
||||
|
#: code:addons/pos_container/static/src/js/container.js:374 |
||||
|
#: code:addons/pos_container/static/src/xml/pos.xml:6 |
||||
|
#: code:addons/pos_container/static/src/xml/pos.xml:135 |
||||
|
#: model:ir.model.fields,field_description:pos_container.field_pos_order_line__container_id |
||||
|
#, python-format |
||||
|
msgid "Container" |
||||
|
msgstr "Contenants" |
||||
|
|
||||
|
#. module: pos_container |
||||
|
#: model:ir.model.fields,field_description:pos_container.field_pos_order_line__container_weight |
||||
|
msgid "Container Weight" |
||||
|
msgstr "Poids du contenant" |
||||
|
|
||||
|
#. module: pos_container |
||||
|
#. openerp-web |
||||
|
#: code:addons/pos_container/static/src/js/container.js:80 |
||||
|
#, python-format |
||||
|
msgid "Container deletion" |
||||
|
msgstr "Suppression de contenant" |
||||
|
|
||||
|
#. module: pos_container |
||||
|
#: model:ir.model,name:pos_container.model_pos_container |
||||
|
msgid "Container for bulk items" |
||||
|
msgstr "Contenant pour produits en vrac" |
||||
|
|
||||
|
#. module: pos_container |
||||
|
#. openerp-web |
||||
|
#: code:addons/pos_container/static/src/xml/pos.xml:134 |
||||
|
#, python-format |
||||
|
msgid "Container name:" |
||||
|
msgstr "Nom du contenant:" |
||||
|
|
||||
|
#. module: pos_container |
||||
|
#: selection:barcode.rule,type:0 |
||||
|
msgid "Container unit" |
||||
|
msgstr "Unité de contenant" |
||||
|
|
||||
|
#. module: pos_container |
||||
|
#: model:product.product,name:pos_container.temporary_container_product |
||||
|
#: model:product.template,name:pos_container.temporary_container_product_product_template |
||||
|
msgid "Container without product" |
||||
|
msgstr "Contenant sans produit" |
||||
|
|
||||
|
#. module: pos_container |
||||
|
#: model:ir.actions.act_window,name:pos_container.pos_container_action_window |
||||
|
#: model:ir.ui.menu,name:pos_container.pos_container_menu |
||||
|
msgid "Containers" |
||||
|
msgstr "Contenants" |
||||
|
|
||||
|
#. module: pos_container |
||||
|
#: model:ir.model.fields,field_description:pos_container.field_pos_container__create_uid |
||||
|
msgid "Created by" |
||||
|
msgstr "Créé par" |
||||
|
|
||||
|
#. module: pos_container |
||||
|
#: model:ir.model.fields,field_description:pos_container.field_pos_container__create_date |
||||
|
msgid "Created on" |
||||
|
msgstr "Créé le" |
||||
|
|
||||
|
#. module: pos_container |
||||
|
#. openerp-web |
||||
|
#: code:addons/pos_container/static/src/xml/pos.xml:30 |
||||
|
#, python-format |
||||
|
msgid "Delete container" |
||||
|
msgstr "Supprimer le contenant" |
||||
|
|
||||
|
#. module: pos_container |
||||
|
#. openerp-web |
||||
|
#: code:addons/pos_container/static/src/xml/pos.xml:295 |
||||
|
#: code:addons/pos_container/static/src/xml/pos.xml:335 |
||||
|
#: code:addons/pos_container/static/src/xml/pos.xml:383 |
||||
|
#, python-format |
||||
|
msgid "Discount:" |
||||
|
msgstr "Réduction:" |
||||
|
|
||||
|
#. module: pos_container |
||||
|
#: selection:barcode.rule,type:0 |
||||
|
msgid "Discounted Product" |
||||
|
msgstr "Article en promotion" |
||||
|
|
||||
|
#. module: pos_container |
||||
|
#: model:ir.model.fields,field_description:pos_container.field_pos_container__display_name |
||||
|
msgid "Display Name" |
||||
|
msgstr "Nom affiché" |
||||
|
|
||||
|
#. module: pos_container |
||||
|
#. openerp-web |
||||
|
#: code:addons/pos_container/static/src/js/container.js:81 |
||||
|
#, python-format |
||||
|
msgid "Do you want to delete this container ?\n" |
||||
|
msgstr "Voulez-vous supprimer ce contenant ?\n" |
||||
|
|
||||
|
#. module: pos_container |
||||
|
#. openerp-web |
||||
|
#: code:addons/pos_container/static/src/js/container.js:144 |
||||
|
#, python-format |
||||
|
msgid "Error: Could not Save Changes" |
||||
|
msgstr "Erreur: Impossible de sauvegarder les changements" |
||||
|
|
||||
|
#. module: pos_container |
||||
|
#. openerp-web |
||||
|
#: code:addons/pos_container/static/src/xml/pos.xml:84 |
||||
|
#: code:addons/pos_container/static/src/xml/pos.xml:101 |
||||
|
#, python-format |
||||
|
msgid "Gross :" |
||||
|
msgstr "Poids Brut :" |
||||
|
|
||||
|
#. module: pos_container |
||||
|
#: model:ir.model.fields,field_description:pos_container.field_pos_container__id |
||||
|
msgid "ID" |
||||
|
msgstr "ID" |
||||
|
|
||||
|
#. module: pos_container |
||||
|
#: model:ir.model.fields,field_description:pos_container.field_pos_container____last_update |
||||
|
msgid "Last Modified on" |
||||
|
msgstr "Dernière modification le" |
||||
|
|
||||
|
#. module: pos_container |
||||
|
#: model:ir.model.fields,field_description:pos_container.field_pos_container__write_uid |
||||
|
msgid "Last Updated by" |
||||
|
msgstr "Dernière mise à jour par" |
||||
|
|
||||
|
#. module: pos_container |
||||
|
#: model:ir.model.fields,field_description:pos_container.field_pos_container__write_date |
||||
|
msgid "Last Updated on" |
||||
|
msgstr "Dernière mise à jour le" |
||||
|
|
||||
|
#. module: pos_container |
||||
|
#: selection:barcode.rule,type:0 |
||||
|
msgid "Location" |
||||
|
msgstr "Lieu" |
||||
|
|
||||
|
#. module: pos_container |
||||
|
#: selection:barcode.rule,type:0 |
||||
|
msgid "Lot" |
||||
|
msgstr "Lot" |
||||
|
|
||||
|
#. module: pos_container |
||||
|
#. openerp-web |
||||
|
#: code:addons/pos_container/static/src/xml/pos.xml:234 |
||||
|
#: code:addons/pos_container/static/src/xml/pos.xml:366 |
||||
|
#, python-format |
||||
|
msgid "Manual Input" |
||||
|
msgstr "Saisie manuelle" |
||||
|
|
||||
|
#. module: pos_container |
||||
|
#. openerp-web |
||||
|
#: code:addons/pos_container/static/src/xml/pos.xml:47 |
||||
|
#: model:ir.model.fields,field_description:pos_container.field_pos_container__name |
||||
|
#, python-format |
||||
|
msgid "Name" |
||||
|
msgstr "Nom" |
||||
|
|
||||
|
#. module: pos_container |
||||
|
#: model:ir.model.fields,field_description:pos_container.field_pos_container__owner_id |
||||
|
msgid "Owner" |
||||
|
msgstr "Propriétaire" |
||||
|
|
||||
|
#. module: pos_container |
||||
|
#: selection:barcode.rule,type:0 |
||||
|
msgid "Package" |
||||
|
msgstr "Colis" |
||||
|
|
||||
|
#. module: pos_container |
||||
|
#: model:ir.model,name:pos_container.model_pos_order_line |
||||
|
msgid "Point of Sale Order Lines" |
||||
|
msgstr "Lignes de Commande en Point de Vente" |
||||
|
|
||||
|
#. module: pos_container |
||||
|
#: selection:barcode.rule,type:0 |
||||
|
msgid "Priced Product" |
||||
|
msgstr "Article à prix fixe" |
||||
|
|
||||
|
#. module: pos_container |
||||
|
#. openerp-web |
||||
|
#: code:addons/pos_container/static/src/xml/pos.xml:137 |
||||
|
#, python-format |
||||
|
msgid "Save" |
||||
|
msgstr "Sauvegarder" |
||||
|
|
||||
|
#. module: pos_container |
||||
|
#. openerp-web |
||||
|
#: code:addons/pos_container/static/src/xml/pos.xml:26 |
||||
|
#, python-format |
||||
|
msgid "Search Containers" |
||||
|
msgstr "Recherche contenant" |
||||
|
|
||||
|
#. module: pos_container |
||||
|
#. openerp-web |
||||
|
#: code:addons/pos_container/static/src/xml/pos.xml:34 |
||||
|
#, python-format |
||||
|
msgid "Select a container" |
||||
|
msgstr "Sélection contenant" |
||||
|
|
||||
|
#. module: pos_container |
||||
|
#. openerp-web |
||||
|
#: code:addons/pos_container/static/src/xml/pos.xml:12 |
||||
|
#: model:ir.model.fields,field_description:pos_container.field_pos_order_line__tare |
||||
|
#, python-format |
||||
|
msgid "Tare" |
||||
|
msgstr "Tare" |
||||
|
|
||||
|
#. module: pos_container |
||||
|
#. openerp-web |
||||
|
#: code:addons/pos_container/static/src/xml/pos.xml:215 |
||||
|
#: code:addons/pos_container/static/src/xml/pos.xml:266 |
||||
|
#: code:addons/pos_container/static/src/xml/pos.xml:356 |
||||
|
#: code:addons/pos_container/static/src/xml/pos.xml:404 |
||||
|
#, python-format |
||||
|
msgid "Tare :" |
||||
|
msgstr "PT :" |
||||
|
|
||||
|
#. module: pos_container |
||||
|
#: model:ir.model.fields,field_description:pos_container.field_barcode_rule__type |
||||
|
msgid "Type" |
||||
|
msgstr "Type" |
||||
|
|
||||
|
#. module: pos_container |
||||
|
#: selection:barcode.rule,type:0 |
||||
|
msgid "Unit Product" |
||||
|
msgstr "Unité de produit" |
||||
|
|
||||
|
#. module: pos_container |
||||
|
#. openerp-web |
||||
|
#: code:addons/pos_container/static/src/xml/pos.xml:49 |
||||
|
#, python-format |
||||
|
msgid "Weight" |
||||
|
msgstr "Poids" |
||||
|
|
||||
|
#. module: pos_container |
||||
|
#: model:ir.model.fields,field_description:pos_container.field_pos_container__weight |
||||
|
msgid "Weight (g)" |
||||
|
msgstr "Poids (kg)" |
||||
|
|
||||
|
#. module: pos_container |
||||
|
#: selection:barcode.rule,type:0 |
||||
|
msgid "Weighted Product" |
||||
|
msgstr "Article pesé" |
||||
|
|
||||
|
#. module: pos_container |
||||
|
#. openerp-web |
||||
|
#: code:addons/pos_container/static/src/xml/pos.xml:160 |
||||
|
#: code:addons/pos_container/static/src/xml/pos.xml:201 |
||||
|
#: code:addons/pos_container/static/src/xml/pos.xml:251 |
||||
|
#, python-format |
||||
|
msgid "With a" |
||||
|
msgstr "Avec un" |
||||
|
|
||||
|
#. module: pos_container |
||||
|
#. openerp-web |
||||
|
#: code:addons/pos_container/static/src/js/container.js:138 |
||||
|
#, python-format |
||||
|
msgid "Your Internet connection is probably down." |
||||
|
msgstr "Votre connexion internet est probablement coupée." |
||||
|
|
||||
|
#. module: pos_container |
||||
|
#. openerp-web |
||||
|
#: code:addons/pos_container/static/src/xml/pos.xml:85 |
||||
|
#: code:addons/pos_container/static/src/xml/pos.xml:102 |
||||
|
#: model:product.product,uom_name:pos_container.temporary_container_product |
||||
|
#: model:product.product,weight_uom_name:pos_container.temporary_container_product |
||||
|
#: model:product.template,uom_name:pos_container.temporary_container_product_product_template |
||||
|
#: model:product.template,weight_uom_name:pos_container.temporary_container_product_product_template |
||||
|
#, python-format |
||||
|
msgid "kg" |
||||
|
msgstr "kg" |
||||
|
|
||||
|
#. module: pos_container |
||||
|
#. openerp-web |
||||
|
#: code:addons/pos_container/static/src/xml/pos.xml:90 |
||||
|
#, python-format |
||||
|
msgid "" |
||||
|
"kg \n" |
||||
|
" -" |
||||
|
msgstr "" |
||||
|
"kg\n" |
||||
|
" -" |
||||
|
|
||||
|
#. module: pos_container |
||||
|
#. openerp-web |
||||
|
#: code:addons/pos_container/static/src/xml/pos.xml:107 |
||||
|
#, python-format |
||||
|
msgid "" |
||||
|
"kg \n" |
||||
|
" - Manual tare" |
||||
|
msgstr "" |
||||
|
"kg \n" |
||||
|
" - Tare manuelle" |
@ -0,0 +1,377 @@ |
|||||
|
# Translation of Odoo Server. |
||||
|
# This file contains the translation of the following modules: |
||||
|
# * pos_container |
||||
|
# |
||||
|
msgid "" |
||||
|
msgstr "" |
||||
|
"Project-Id-Version: Odoo Server 12.0\n" |
||||
|
"Report-Msgid-Bugs-To: \n" |
||||
|
"POT-Creation-Date: 2019-11-19 09:33+0000\n" |
||||
|
"PO-Revision-Date: 2019-11-19 09:33+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: pos_container |
||||
|
#: model:product.product,description:pos_container.temporary_container_product |
||||
|
#: model:product.template,description:pos_container.temporary_container_product_product_template |
||||
|
msgid "\n" |
||||
|
" This product is used to describe POS order lines having a container but no product yet\n" |
||||
|
" " |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_container |
||||
|
#. openerp-web |
||||
|
#: code:addons/pos_container/static/src/xml/pos.xml:161 |
||||
|
#: code:addons/pos_container/static/src/xml/pos.xml:202 |
||||
|
#: code:addons/pos_container/static/src/xml/pos.xml:252 |
||||
|
#, python-format |
||||
|
msgid "% discount" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_container |
||||
|
#. openerp-web |
||||
|
#: code:addons/pos_container/static/src/xml/pos.xml:127 |
||||
|
#, python-format |
||||
|
msgid "Add a container" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_container |
||||
|
#: selection:barcode.rule,type:0 |
||||
|
msgid "Alias" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_container |
||||
|
#. openerp-web |
||||
|
#: code:addons/pos_container/static/src/xml/pos.xml:184 |
||||
|
#: code:addons/pos_container/static/src/xml/pos.xml:318 |
||||
|
#, python-format |
||||
|
msgid "Automatic Weighing" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_container |
||||
|
#. openerp-web |
||||
|
#: code:addons/pos_container/static/src/xml/pos.xml:124 |
||||
|
#, python-format |
||||
|
msgid "Back" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_container |
||||
|
#. openerp-web |
||||
|
#: code:addons/pos_container/static/src/xml/pos.xml:48 |
||||
|
#: model:ir.model.fields,field_description:pos_container.field_pos_container__barcode |
||||
|
#, python-format |
||||
|
msgid "Barcode" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_container |
||||
|
#: model:ir.model,name:pos_container.model_barcode_rule |
||||
|
msgid "Barcode Rule" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_container |
||||
|
#. openerp-web |
||||
|
#: code:addons/pos_container/static/src/xml/pos.xml:22 |
||||
|
#, python-format |
||||
|
msgid "Cancel" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_container |
||||
|
#: selection:barcode.rule,type:0 |
||||
|
msgid "Cashier" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_container |
||||
|
#: selection:barcode.rule,type:0 |
||||
|
msgid "Client" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_container |
||||
|
#. openerp-web |
||||
|
#: code:addons/pos_container/static/src/js/container.js:374 |
||||
|
#: code:addons/pos_container/static/src/xml/pos.xml:6 |
||||
|
#: code:addons/pos_container/static/src/xml/pos.xml:135 |
||||
|
#: model:ir.model.fields,field_description:pos_container.field_pos_order_line__container_id |
||||
|
#, python-format |
||||
|
msgid "Container" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_container |
||||
|
#: model:ir.model.fields,field_description:pos_container.field_pos_order_line__container_weight |
||||
|
msgid "Container Weight" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_container |
||||
|
#. openerp-web |
||||
|
#: code:addons/pos_container/static/src/js/container.js:80 |
||||
|
#, python-format |
||||
|
msgid "Container deletion" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_container |
||||
|
#: model:ir.model,name:pos_container.model_pos_container |
||||
|
msgid "Container for bulk items" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_container |
||||
|
#. openerp-web |
||||
|
#: code:addons/pos_container/static/src/xml/pos.xml:134 |
||||
|
#, python-format |
||||
|
msgid "Container name:" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_container |
||||
|
#: selection:barcode.rule,type:0 |
||||
|
msgid "Container unit" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_container |
||||
|
#: model:product.product,name:pos_container.temporary_container_product |
||||
|
#: model:product.template,name:pos_container.temporary_container_product_product_template |
||||
|
msgid "Container without product" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_container |
||||
|
#: model:ir.actions.act_window,name:pos_container.pos_container_action_window |
||||
|
#: model:ir.ui.menu,name:pos_container.pos_container_menu |
||||
|
msgid "Containers" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_container |
||||
|
#: model:ir.model.fields,field_description:pos_container.field_pos_container__create_uid |
||||
|
msgid "Created by" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_container |
||||
|
#: model:ir.model.fields,field_description:pos_container.field_pos_container__create_date |
||||
|
msgid "Created on" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_container |
||||
|
#. openerp-web |
||||
|
#: code:addons/pos_container/static/src/xml/pos.xml:30 |
||||
|
#, python-format |
||||
|
msgid "Delete container" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_container |
||||
|
#. openerp-web |
||||
|
#: code:addons/pos_container/static/src/xml/pos.xml:295 |
||||
|
#: code:addons/pos_container/static/src/xml/pos.xml:335 |
||||
|
#: code:addons/pos_container/static/src/xml/pos.xml:383 |
||||
|
#, python-format |
||||
|
msgid "Discount:" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_container |
||||
|
#: selection:barcode.rule,type:0 |
||||
|
msgid "Discounted Product" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_container |
||||
|
#: model:ir.model.fields,field_description:pos_container.field_pos_container__display_name |
||||
|
msgid "Display Name" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_container |
||||
|
#. openerp-web |
||||
|
#: code:addons/pos_container/static/src/js/container.js:81 |
||||
|
#, python-format |
||||
|
msgid "Do you want to delete this container ?\n" |
||||
|
"" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_container |
||||
|
#. openerp-web |
||||
|
#: code:addons/pos_container/static/src/js/container.js:144 |
||||
|
#, python-format |
||||
|
msgid "Error: Could not Save Changes" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_container |
||||
|
#. openerp-web |
||||
|
#: code:addons/pos_container/static/src/xml/pos.xml:84 |
||||
|
#: code:addons/pos_container/static/src/xml/pos.xml:101 |
||||
|
#, python-format |
||||
|
msgid "Gross :" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_container |
||||
|
#: model:ir.model.fields,field_description:pos_container.field_pos_container__id |
||||
|
msgid "ID" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_container |
||||
|
#: model:ir.model.fields,field_description:pos_container.field_pos_container____last_update |
||||
|
msgid "Last Modified on" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_container |
||||
|
#: model:ir.model.fields,field_description:pos_container.field_pos_container__write_uid |
||||
|
msgid "Last Updated by" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_container |
||||
|
#: model:ir.model.fields,field_description:pos_container.field_pos_container__write_date |
||||
|
msgid "Last Updated on" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_container |
||||
|
#: selection:barcode.rule,type:0 |
||||
|
msgid "Location" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_container |
||||
|
#: selection:barcode.rule,type:0 |
||||
|
msgid "Lot" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_container |
||||
|
#. openerp-web |
||||
|
#: code:addons/pos_container/static/src/xml/pos.xml:234 |
||||
|
#: code:addons/pos_container/static/src/xml/pos.xml:366 |
||||
|
#, python-format |
||||
|
msgid "Manual Input" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_container |
||||
|
#. openerp-web |
||||
|
#: code:addons/pos_container/static/src/xml/pos.xml:47 |
||||
|
#: model:ir.model.fields,field_description:pos_container.field_pos_container__name |
||||
|
#, python-format |
||||
|
msgid "Name" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_container |
||||
|
#: model:ir.model.fields,field_description:pos_container.field_pos_container__owner_id |
||||
|
msgid "Owner" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_container |
||||
|
#: selection:barcode.rule,type:0 |
||||
|
msgid "Package" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_container |
||||
|
#: model:ir.model,name:pos_container.model_pos_order_line |
||||
|
msgid "Point of Sale Order Lines" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_container |
||||
|
#: selection:barcode.rule,type:0 |
||||
|
msgid "Priced Product" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_container |
||||
|
#. openerp-web |
||||
|
#: code:addons/pos_container/static/src/xml/pos.xml:137 |
||||
|
#, python-format |
||||
|
msgid "Save" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_container |
||||
|
#. openerp-web |
||||
|
#: code:addons/pos_container/static/src/xml/pos.xml:26 |
||||
|
#, python-format |
||||
|
msgid "Search Containers" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_container |
||||
|
#. openerp-web |
||||
|
#: code:addons/pos_container/static/src/xml/pos.xml:34 |
||||
|
#, python-format |
||||
|
msgid "Select a container" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_container |
||||
|
#. openerp-web |
||||
|
#: code:addons/pos_container/static/src/xml/pos.xml:12 |
||||
|
#: model:ir.model.fields,field_description:pos_container.field_pos_order_line__tare |
||||
|
#, python-format |
||||
|
msgid "Tare" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_container |
||||
|
#. openerp-web |
||||
|
#: code:addons/pos_container/static/src/xml/pos.xml:215 |
||||
|
#: code:addons/pos_container/static/src/xml/pos.xml:266 |
||||
|
#: code:addons/pos_container/static/src/xml/pos.xml:356 |
||||
|
#: code:addons/pos_container/static/src/xml/pos.xml:404 |
||||
|
#, python-format |
||||
|
msgid "Tare :" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_container |
||||
|
#: model:ir.model.fields,field_description:pos_container.field_barcode_rule__type |
||||
|
msgid "Type" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_container |
||||
|
#: selection:barcode.rule,type:0 |
||||
|
msgid "Unit Product" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_container |
||||
|
#. openerp-web |
||||
|
#: code:addons/pos_container/static/src/xml/pos.xml:49 |
||||
|
#, python-format |
||||
|
msgid "Weight" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_container |
||||
|
#: model:ir.model.fields,field_description:pos_container.field_pos_container__weight |
||||
|
msgid "Weight (g)" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_container |
||||
|
#: selection:barcode.rule,type:0 |
||||
|
msgid "Weighted Product" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_container |
||||
|
#. openerp-web |
||||
|
#: code:addons/pos_container/static/src/xml/pos.xml:160 |
||||
|
#: code:addons/pos_container/static/src/xml/pos.xml:201 |
||||
|
#: code:addons/pos_container/static/src/xml/pos.xml:251 |
||||
|
#, python-format |
||||
|
msgid "With a" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_container |
||||
|
#. openerp-web |
||||
|
#: code:addons/pos_container/static/src/js/container.js:138 |
||||
|
#, python-format |
||||
|
msgid "Your Internet connection is probably down." |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_container |
||||
|
#. openerp-web |
||||
|
#: code:addons/pos_container/static/src/xml/pos.xml:85 |
||||
|
#: code:addons/pos_container/static/src/xml/pos.xml:102 |
||||
|
#: model:product.product,uom_name:pos_container.temporary_container_product |
||||
|
#: model:product.product,weight_uom_name:pos_container.temporary_container_product |
||||
|
#: model:product.template,uom_name:pos_container.temporary_container_product_product_template |
||||
|
#: model:product.template,weight_uom_name:pos_container.temporary_container_product_product_template |
||||
|
#, python-format |
||||
|
msgid "kg" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_container |
||||
|
#. openerp-web |
||||
|
#: code:addons/pos_container/static/src/xml/pos.xml:90 |
||||
|
#, python-format |
||||
|
msgid "kg \n" |
||||
|
" -" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_container |
||||
|
#. openerp-web |
||||
|
#: code:addons/pos_container/static/src/xml/pos.xml:107 |
||||
|
#, python-format |
||||
|
msgid "kg \n" |
||||
|
" - Manual tare" |
||||
|
msgstr "" |
||||
|
|
@ -0,0 +1,3 @@ |
|||||
|
from . import container |
||||
|
from . import barcode |
||||
|
from . import pos_order_line |
@ -0,0 +1,13 @@ |
|||||
|
# Copyright 2019 Coop IT Easy SCRLfs |
||||
|
# Pierrick Brun <pierrick.brun@akretion.com> |
||||
|
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). |
||||
|
|
||||
|
from odoo import models, fields |
||||
|
|
||||
|
|
||||
|
class BarcodeRule(models.Model): |
||||
|
_inherit = 'barcode.rule' |
||||
|
|
||||
|
type = fields.Selection( |
||||
|
selection_add=[('container', 'Container unit')], |
||||
|
) |
@ -0,0 +1,45 @@ |
|||||
|
# Copyright 2019 Coop IT Easy SCRLfs |
||||
|
# Robin Keunen <robin@coopiteasy.be> |
||||
|
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). |
||||
|
|
||||
|
from odoo import models, fields, api |
||||
|
|
||||
|
|
||||
|
class Container(models.Model): |
||||
|
_name = 'pos.container' |
||||
|
_description = 'Container for bulk items' |
||||
|
|
||||
|
name = fields.Char( |
||||
|
string='Name', |
||||
|
) |
||||
|
barcode = fields.Char( |
||||
|
'Barcode', |
||||
|
size=13, |
||||
|
) |
||||
|
weight = fields.Float( |
||||
|
string='Weight (kg)', |
||||
|
) |
||||
|
owner_id = fields.Many2one( |
||||
|
comodel_name='res.partner', |
||||
|
inverse_name='container_ids', |
||||
|
string='Owner', |
||||
|
) |
||||
|
|
||||
|
_sql_constraints = [ |
||||
|
('barcode_uniq', |
||||
|
'unique(barcode)', |
||||
|
"A barcode can only be assigned to one container !"), |
||||
|
] |
||||
|
|
||||
|
@api.model |
||||
|
def create_from_ui(self, containers): |
||||
|
# retourne la liste des ids dans le même ordre que la liste fournie |
||||
|
container_ids = [] |
||||
|
for container in containers: |
||||
|
container_id = container.pop('id', False) |
||||
|
if container_id: # Modifying existing container |
||||
|
self.browse(container_id).write(container) |
||||
|
else: |
||||
|
container_id = self.create(container).id |
||||
|
container_ids.append(container_id) |
||||
|
return container_ids |
@ -0,0 +1,15 @@ |
|||||
|
# Copyright 2019 Coop IT Easy SCRLfs |
||||
|
# @author Pierrick Brun <pierrick.brun@akretion.com> |
||||
|
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). |
||||
|
|
||||
|
from odoo import fields, models |
||||
|
|
||||
|
|
||||
|
class PosOrderLine(models.Model): |
||||
|
_inherit = 'pos.order.line' |
||||
|
|
||||
|
tare = fields.Float('Tare') |
||||
|
container_weight = fields.Float('Container Weight') |
||||
|
container_id = fields.Many2one( |
||||
|
'pos.container', |
||||
|
'Container') |
@ -0,0 +1,2 @@ |
|||||
|
* Pierrick Brun <pierrick.brun@akretion.com> |
||||
|
* Robin Keunen <robin.keunen@coopiteasy.be> |
@ -0,0 +1,5 @@ |
|||||
|
This module allows to handle use of reusable containers in POS, |
||||
|
this is useful to handle selling product in bulk without having to calculate |
||||
|
the tare of the container. |
||||
|
|
||||
|
Each container is identified by a barcode, the weight is stored in Odoo. |
@ -0,0 +1,2 @@ |
|||||
|
You have to create a Barcode Nomenclature to handle containers before using the |
||||
|
module. |
@ -0,0 +1,3 @@ |
|||||
|
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink |
||||
|
access_pos_container_pos_user,access_pos_container_pos_user,model_pos_container,point_of_sale.group_pos_user,1,1,1,1 |
||||
|
access_pos_container_pos_manager,access_pos_container_pos_manager,model_pos_container,point_of_sale.group_pos_manager,1,1,1,1 |
@ -0,0 +1,431 @@ |
|||||
|
<?xml version="1.0" encoding="utf-8" ?> |
||||
|
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> |
||||
|
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> |
||||
|
<head> |
||||
|
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> |
||||
|
<meta name="generator" content="Docutils 0.14: http://docutils.sourceforge.net/" /> |
||||
|
<title>POS Container</title> |
||||
|
<style type="text/css"> |
||||
|
|
||||
|
/* |
||||
|
:Author: David Goodger (goodger@python.org) |
||||
|
:Id: $Id: html4css1.css 7952 2016-07-26 18:15:59Z milde $ |
||||
|
:Copyright: This stylesheet has been placed in the public domain. |
||||
|
|
||||
|
Default cascading style sheet for the HTML output of Docutils. |
||||
|
|
||||
|
See http://docutils.sf.net/docs/howto/html-stylesheets.html for how to |
||||
|
customize this style sheet. |
||||
|
*/ |
||||
|
|
||||
|
/* used to remove borders from tables and images */ |
||||
|
.borderless, table.borderless td, table.borderless th { |
||||
|
border: 0 } |
||||
|
|
||||
|
table.borderless td, table.borderless th { |
||||
|
/* Override padding for "table.docutils td" with "! important". |
||||
|
The right padding separates the table cells. */ |
||||
|
padding: 0 0.5em 0 0 ! important } |
||||
|
|
||||
|
.first { |
||||
|
/* Override more specific margin styles with "! important". */ |
||||
|
margin-top: 0 ! important } |
||||
|
|
||||
|
.last, .with-subtitle { |
||||
|
margin-bottom: 0 ! important } |
||||
|
|
||||
|
.hidden { |
||||
|
display: none } |
||||
|
|
||||
|
.subscript { |
||||
|
vertical-align: sub; |
||||
|
font-size: smaller } |
||||
|
|
||||
|
.superscript { |
||||
|
vertical-align: super; |
||||
|
font-size: smaller } |
||||
|
|
||||
|
a.toc-backref { |
||||
|
text-decoration: none ; |
||||
|
color: black } |
||||
|
|
||||
|
blockquote.epigraph { |
||||
|
margin: 2em 5em ; } |
||||
|
|
||||
|
dl.docutils dd { |
||||
|
margin-bottom: 0.5em } |
||||
|
|
||||
|
object[type="image/svg+xml"], object[type="application/x-shockwave-flash"] { |
||||
|
overflow: hidden; |
||||
|
} |
||||
|
|
||||
|
/* Uncomment (and remove this text!) to get bold-faced definition list terms |
||||
|
dl.docutils dt { |
||||
|
font-weight: bold } |
||||
|
*/ |
||||
|
|
||||
|
div.abstract { |
||||
|
margin: 2em 5em } |
||||
|
|
||||
|
div.abstract p.topic-title { |
||||
|
font-weight: bold ; |
||||
|
text-align: center } |
||||
|
|
||||
|
div.admonition, div.attention, div.caution, div.danger, div.error, |
||||
|
div.hint, div.important, div.note, div.tip, div.warning { |
||||
|
margin: 2em ; |
||||
|
border: medium outset ; |
||||
|
padding: 1em } |
||||
|
|
||||
|
div.admonition p.admonition-title, div.hint p.admonition-title, |
||||
|
div.important p.admonition-title, div.note p.admonition-title, |
||||
|
div.tip p.admonition-title { |
||||
|
font-weight: bold ; |
||||
|
font-family: sans-serif } |
||||
|
|
||||
|
div.attention p.admonition-title, div.caution p.admonition-title, |
||||
|
div.danger p.admonition-title, div.error p.admonition-title, |
||||
|
div.warning p.admonition-title, .code .error { |
||||
|
color: red ; |
||||
|
font-weight: bold ; |
||||
|
font-family: sans-serif } |
||||
|
|
||||
|
/* Uncomment (and remove this text!) to get reduced vertical space in |
||||
|
compound paragraphs. |
||||
|
div.compound .compound-first, div.compound .compound-middle { |
||||
|
margin-bottom: 0.5em } |
||||
|
|
||||
|
div.compound .compound-last, div.compound .compound-middle { |
||||
|
margin-top: 0.5em } |
||||
|
*/ |
||||
|
|
||||
|
div.dedication { |
||||
|
margin: 2em 5em ; |
||||
|
text-align: center ; |
||||
|
font-style: italic } |
||||
|
|
||||
|
div.dedication p.topic-title { |
||||
|
font-weight: bold ; |
||||
|
font-style: normal } |
||||
|
|
||||
|
div.figure { |
||||
|
margin-left: 2em ; |
||||
|
margin-right: 2em } |
||||
|
|
||||
|
div.footer, div.header { |
||||
|
clear: both; |
||||
|
font-size: smaller } |
||||
|
|
||||
|
div.line-block { |
||||
|
display: block ; |
||||
|
margin-top: 1em ; |
||||
|
margin-bottom: 1em } |
||||
|
|
||||
|
div.line-block div.line-block { |
||||
|
margin-top: 0 ; |
||||
|
margin-bottom: 0 ; |
||||
|
margin-left: 1.5em } |
||||
|
|
||||
|
div.sidebar { |
||||
|
margin: 0 0 0.5em 1em ; |
||||
|
border: medium outset ; |
||||
|
padding: 1em ; |
||||
|
background-color: #ffffee ; |
||||
|
width: 40% ; |
||||
|
float: right ; |
||||
|
clear: right } |
||||
|
|
||||
|
div.sidebar p.rubric { |
||||
|
font-family: sans-serif ; |
||||
|
font-size: medium } |
||||
|
|
||||
|
div.system-messages { |
||||
|
margin: 5em } |
||||
|
|
||||
|
div.system-messages h1 { |
||||
|
color: red } |
||||
|
|
||||
|
div.system-message { |
||||
|
border: medium outset ; |
||||
|
padding: 1em } |
||||
|
|
||||
|
div.system-message p.system-message-title { |
||||
|
color: red ; |
||||
|
font-weight: bold } |
||||
|
|
||||
|
div.topic { |
||||
|
margin: 2em } |
||||
|
|
||||
|
h1.section-subtitle, h2.section-subtitle, h3.section-subtitle, |
||||
|
h4.section-subtitle, h5.section-subtitle, h6.section-subtitle { |
||||
|
margin-top: 0.4em } |
||||
|
|
||||
|
h1.title { |
||||
|
text-align: center } |
||||
|
|
||||
|
h2.subtitle { |
||||
|
text-align: center } |
||||
|
|
||||
|
hr.docutils { |
||||
|
width: 75% } |
||||
|
|
||||
|
img.align-left, .figure.align-left, object.align-left, table.align-left { |
||||
|
clear: left ; |
||||
|
float: left ; |
||||
|
margin-right: 1em } |
||||
|
|
||||
|
img.align-right, .figure.align-right, object.align-right, table.align-right { |
||||
|
clear: right ; |
||||
|
float: right ; |
||||
|
margin-left: 1em } |
||||
|
|
||||
|
img.align-center, .figure.align-center, object.align-center { |
||||
|
display: block; |
||||
|
margin-left: auto; |
||||
|
margin-right: auto; |
||||
|
} |
||||
|
|
||||
|
table.align-center { |
||||
|
margin-left: auto; |
||||
|
margin-right: auto; |
||||
|
} |
||||
|
|
||||
|
.align-left { |
||||
|
text-align: left } |
||||
|
|
||||
|
.align-center { |
||||
|
clear: both ; |
||||
|
text-align: center } |
||||
|
|
||||
|
.align-right { |
||||
|
text-align: right } |
||||
|
|
||||
|
/* reset inner alignment in figures */ |
||||
|
div.align-right { |
||||
|
text-align: inherit } |
||||
|
|
||||
|
/* div.align-center * { */ |
||||
|
/* text-align: left } */ |
||||
|
|
||||
|
.align-top { |
||||
|
vertical-align: top } |
||||
|
|
||||
|
.align-middle { |
||||
|
vertical-align: middle } |
||||
|
|
||||
|
.align-bottom { |
||||
|
vertical-align: bottom } |
||||
|
|
||||
|
ol.simple, ul.simple { |
||||
|
margin-bottom: 1em } |
||||
|
|
||||
|
ol.arabic { |
||||
|
list-style: decimal } |
||||
|
|
||||
|
ol.loweralpha { |
||||
|
list-style: lower-alpha } |
||||
|
|
||||
|
ol.upperalpha { |
||||
|
list-style: upper-alpha } |
||||
|
|
||||
|
ol.lowerroman { |
||||
|
list-style: lower-roman } |
||||
|
|
||||
|
ol.upperroman { |
||||
|
list-style: upper-roman } |
||||
|
|
||||
|
p.attribution { |
||||
|
text-align: right ; |
||||
|
margin-left: 50% } |
||||
|
|
||||
|
p.caption { |
||||
|
font-style: italic } |
||||
|
|
||||
|
p.credits { |
||||
|
font-style: italic ; |
||||
|
font-size: smaller } |
||||
|
|
||||
|
p.label { |
||||
|
white-space: nowrap } |
||||
|
|
||||
|
p.rubric { |
||||
|
font-weight: bold ; |
||||
|
font-size: larger ; |
||||
|
color: maroon ; |
||||
|
text-align: center } |
||||
|
|
||||
|
p.sidebar-title { |
||||
|
font-family: sans-serif ; |
||||
|
font-weight: bold ; |
||||
|
font-size: larger } |
||||
|
|
||||
|
p.sidebar-subtitle { |
||||
|
font-family: sans-serif ; |
||||
|
font-weight: bold } |
||||
|
|
||||
|
p.topic-title { |
||||
|
font-weight: bold } |
||||
|
|
||||
|
pre.address { |
||||
|
margin-bottom: 0 ; |
||||
|
margin-top: 0 ; |
||||
|
font: inherit } |
||||
|
|
||||
|
pre.literal-block, pre.doctest-block, pre.math, pre.code { |
||||
|
margin-left: 2em ; |
||||
|
margin-right: 2em } |
||||
|
|
||||
|
pre.code .ln { color: grey; } /* line numbers */ |
||||
|
pre.code, code { background-color: #eeeeee } |
||||
|
pre.code .comment, code .comment { color: #5C6576 } |
||||
|
pre.code .keyword, code .keyword { color: #3B0D06; font-weight: bold } |
||||
|
pre.code .literal.string, code .literal.string { color: #0C5404 } |
||||
|
pre.code .name.builtin, code .name.builtin { color: #352B84 } |
||||
|
pre.code .deleted, code .deleted { background-color: #DEB0A1} |
||||
|
pre.code .inserted, code .inserted { background-color: #A3D289} |
||||
|
|
||||
|
span.classifier { |
||||
|
font-family: sans-serif ; |
||||
|
font-style: oblique } |
||||
|
|
||||
|
span.classifier-delimiter { |
||||
|
font-family: sans-serif ; |
||||
|
font-weight: bold } |
||||
|
|
||||
|
span.interpreted { |
||||
|
font-family: sans-serif } |
||||
|
|
||||
|
span.option { |
||||
|
white-space: nowrap } |
||||
|
|
||||
|
span.pre { |
||||
|
white-space: pre } |
||||
|
|
||||
|
span.problematic { |
||||
|
color: red } |
||||
|
|
||||
|
span.section-subtitle { |
||||
|
/* font-size relative to parent (h1..h6 element) */ |
||||
|
font-size: 80% } |
||||
|
|
||||
|
table.citation { |
||||
|
border-left: solid 1px gray; |
||||
|
margin-left: 1px } |
||||
|
|
||||
|
table.docinfo { |
||||
|
margin: 2em 4em } |
||||
|
|
||||
|
table.docutils { |
||||
|
margin-top: 0.5em ; |
||||
|
margin-bottom: 0.5em } |
||||
|
|
||||
|
table.footnote { |
||||
|
border-left: solid 1px black; |
||||
|
margin-left: 1px } |
||||
|
|
||||
|
table.docutils td, table.docutils th, |
||||
|
table.docinfo td, table.docinfo th { |
||||
|
padding-left: 0.5em ; |
||||
|
padding-right: 0.5em ; |
||||
|
vertical-align: top } |
||||
|
|
||||
|
table.docutils th.field-name, table.docinfo th.docinfo-name { |
||||
|
font-weight: bold ; |
||||
|
text-align: left ; |
||||
|
white-space: nowrap ; |
||||
|
padding-left: 0 } |
||||
|
|
||||
|
/* "booktabs" style (no vertical lines) */ |
||||
|
table.docutils.booktabs { |
||||
|
border: 0px; |
||||
|
border-top: 2px solid; |
||||
|
border-bottom: 2px solid; |
||||
|
border-collapse: collapse; |
||||
|
} |
||||
|
table.docutils.booktabs * { |
||||
|
border: 0px; |
||||
|
} |
||||
|
table.docutils.booktabs th { |
||||
|
border-bottom: thin solid; |
||||
|
text-align: left; |
||||
|
} |
||||
|
|
||||
|
h1 tt.docutils, h2 tt.docutils, h3 tt.docutils, |
||||
|
h4 tt.docutils, h5 tt.docutils, h6 tt.docutils { |
||||
|
font-size: 100% } |
||||
|
|
||||
|
ul.auto-toc { |
||||
|
list-style-type: none } |
||||
|
|
||||
|
</style> |
||||
|
</head> |
||||
|
<body> |
||||
|
<div class="document" id="pos-container"> |
||||
|
<h1 class="title">POS Container</h1> |
||||
|
|
||||
|
<!-- !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! |
||||
|
!! This file is generated by oca-gen-addon-readme !! |
||||
|
!! changes will be overwritten. !! |
||||
|
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! --> |
||||
|
<p><a class="reference external" href="https://odoo-community.org/page/development-status"><img alt="Beta" src="https://img.shields.io/badge/maturity-Beta-yellow.png" /></a> <a class="reference external" href="https://github.com/OCA/pos/tree/12.0/pos_container"><img alt="OCA/pos" src="https://img.shields.io/badge/github-OCA%2Fpos-lightgray.png?logo=github" /></a> <a class="reference external" href="https://translation.odoo-community.org/projects/pos-12-0/pos-12-0-pos_container"><img alt="Translate me on Weblate" src="https://img.shields.io/badge/weblate-Translate%20me-F47D42.png" /></a> <a class="reference external" href="https://runbot.odoo-community.org/runbot/184/12.0"><img alt="Try me on Runbot" src="https://img.shields.io/badge/runbot-Try%20me-875A7B.png" /></a></p> |
||||
|
<p>This module allows to handle use of reusable containers in POS, |
||||
|
this is useful to handle selling product in bulk without having to calculate |
||||
|
the tare of the container.</p> |
||||
|
<p>Each container is identified by a barcode, the weight is stored in Odoo.</p> |
||||
|
<p><strong>Table of contents</strong></p> |
||||
|
<div class="contents local topic" id="contents"> |
||||
|
<ul class="simple"> |
||||
|
<li><a class="reference internal" href="#usage" id="id1">Usage</a></li> |
||||
|
<li><a class="reference internal" href="#bug-tracker" id="id2">Bug Tracker</a></li> |
||||
|
<li><a class="reference internal" href="#credits" id="id3">Credits</a><ul> |
||||
|
<li><a class="reference internal" href="#authors" id="id4">Authors</a></li> |
||||
|
<li><a class="reference internal" href="#contributors" id="id5">Contributors</a></li> |
||||
|
<li><a class="reference internal" href="#maintainers" id="id6">Maintainers</a></li> |
||||
|
</ul> |
||||
|
</li> |
||||
|
</ul> |
||||
|
</div> |
||||
|
<div class="section" id="usage"> |
||||
|
<h1><a class="toc-backref" href="#id1">Usage</a></h1> |
||||
|
<p>You have to create a Barcode Nomenclature to handle containers before using the |
||||
|
module.</p> |
||||
|
</div> |
||||
|
<div class="section" id="bug-tracker"> |
||||
|
<h1><a class="toc-backref" href="#id2">Bug Tracker</a></h1> |
||||
|
<p>Bugs are tracked on <a class="reference external" href="https://github.com/OCA/pos/issues">GitHub Issues</a>. |
||||
|
In case of trouble, please check there if your issue has already been reported. |
||||
|
If you spotted it first, help us smashing it by providing a detailed and welcomed |
||||
|
<a class="reference external" href="https://github.com/OCA/pos/issues/new?body=module:%20pos_container%0Aversion:%2012.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**">feedback</a>.</p> |
||||
|
<p>Do not contact contributors directly about support or help with technical issues.</p> |
||||
|
</div> |
||||
|
<div class="section" id="credits"> |
||||
|
<h1><a class="toc-backref" href="#id3">Credits</a></h1> |
||||
|
<div class="section" id="authors"> |
||||
|
<h2><a class="toc-backref" href="#id4">Authors</a></h2> |
||||
|
<ul class="simple"> |
||||
|
<li>Coop IT Easy SCRLfs</li> |
||||
|
</ul> |
||||
|
</div> |
||||
|
<div class="section" id="contributors"> |
||||
|
<h2><a class="toc-backref" href="#id5">Contributors</a></h2> |
||||
|
<blockquote> |
||||
|
<ul class="simple"> |
||||
|
<li>Pierrick Brun <<a class="reference external" href="mailto:pierrick.brun@akretion.com">pierrick.brun@akretion.com</a>></li> |
||||
|
<li>Robin Keunen <<a class="reference external" href="mailto:robin.keunen@coopiteasy.be">robin.keunen@coopiteasy.be</a>></li> |
||||
|
</ul> |
||||
|
</blockquote> |
||||
|
</div> |
||||
|
<div class="section" id="maintainers"> |
||||
|
<h2><a class="toc-backref" href="#id6">Maintainers</a></h2> |
||||
|
<p>This module is maintained by the OCA.</p> |
||||
|
<a class="reference external image-reference" href="https://odoo-community.org"><img alt="Odoo Community Association" src="https://odoo-community.org/logo.png" /></a> |
||||
|
<p>OCA, or the Odoo Community Association, is a nonprofit organization whose |
||||
|
mission is to support the collaborative development of Odoo features and |
||||
|
promote its widespread use.</p> |
||||
|
<p>This module is part of the <a class="reference external" href="https://github.com/OCA/pos/tree/12.0/pos_container">OCA/pos</a> project on GitHub.</p> |
||||
|
<p>You are welcome to contribute. To learn how please visit <a class="reference external" href="https://odoo-community.org/page/Contribute">https://odoo-community.org/page/Contribute</a>.</p> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
</body> |
||||
|
</html> |
@ -0,0 +1,191 @@ |
|||||
|
/* firefox seems to ignore the relative positionning of the subwindow-container |
||||
|
* putting this inside subwindow-container fixes it. |
||||
|
*/ |
||||
|
.pos .containerlist-screen .window, |
||||
|
.pos .containerlist-screen .full-content .subwindow{ |
||||
|
display: block; |
||||
|
} |
||||
|
.pos .containerlist-screen .full-content .subwindow-container{ |
||||
|
display: block; |
||||
|
height: 100%; |
||||
|
} |
||||
|
.pos .containerlist-screen .full-content .subwindow.collapsed, |
||||
|
.pos .containerlist-screen .full-content .subwindow-container.collapsed{ |
||||
|
height: auto; |
||||
|
} |
||||
|
|
||||
|
/* The Scale Container Screen */ |
||||
|
.pos .scale-screen .add-container{ |
||||
|
text-align: center; |
||||
|
font-size: 32px; |
||||
|
background: rgb(110,200,155); |
||||
|
color: white; |
||||
|
border-radius: 3px; |
||||
|
padding: 16px; |
||||
|
margin: 16px; |
||||
|
cursor: pointer; |
||||
|
} |
||||
|
|
||||
|
.pos .scale-screen .container-name,.container-barcode{ |
||||
|
text-align: center; |
||||
|
font-size: 25px; |
||||
|
border-radius: 3px; |
||||
|
padding-top: 10px; |
||||
|
padding-bottom:10px; |
||||
|
margin-top: 5px; |
||||
|
} |
||||
|
|
||||
|
/* e) The Container List Screen */ |
||||
|
|
||||
|
.pos .containerlist-screen .container-list{ |
||||
|
font-size: 16px; |
||||
|
width: 100%; |
||||
|
line-height: 40px; |
||||
|
} |
||||
|
.pos .containerlist-screen .container-list th, |
||||
|
.pos .containerlist-screen .container-list td { |
||||
|
padding: 0px 8px; |
||||
|
} |
||||
|
.pos .containerlist-screen .container-list tr{ |
||||
|
transition: all 150ms linear; |
||||
|
background: rgb(230,230,230); |
||||
|
} |
||||
|
.pos .containerlist-screen .container-list thead > tr, |
||||
|
.pos .containerlist-screen .container-list tr:nth-child(even) { |
||||
|
background: rgb(247,247,247); |
||||
|
} |
||||
|
.pos .containerlist-screen .container-list tr.highlight{ |
||||
|
transition: all 150ms linear; |
||||
|
background: rgb(110,200,155) !important; |
||||
|
color: white; |
||||
|
} |
||||
|
.pos .containerlist-screen .container-list tr.lowlight{ |
||||
|
transition: all 150ms linear; |
||||
|
background: rgb(216, 238, 227); |
||||
|
} |
||||
|
.pos .containerlist-screen .container-list tr.lowlight:nth-child(even){ |
||||
|
transition: all 150ms linear; |
||||
|
background: rgb(227, 246, 237); |
||||
|
} |
||||
|
.pos .containerlist-screen .container-details{ |
||||
|
padding: 16px; |
||||
|
border-bottom: solid 5px rgb(110,200,155); |
||||
|
} |
||||
|
.pos .containerlist-screen .container-picture{ |
||||
|
height: 64px; |
||||
|
width: 64px; |
||||
|
border-radius: 32px; |
||||
|
overflow: hidden; |
||||
|
text-align: center; |
||||
|
float: left; |
||||
|
margin-right: 16px; |
||||
|
background: white; |
||||
|
position: relative; |
||||
|
} |
||||
|
.pos .containerlist-screen .container-picture > img { |
||||
|
position: absolute; |
||||
|
top: -9999px; |
||||
|
bottom: -9999px; |
||||
|
right: -9999px; |
||||
|
left: -9999px; |
||||
|
max-height: 64px; |
||||
|
margin: auto; |
||||
|
} |
||||
|
.pos .containerlist-screen .container-picture > .fa { |
||||
|
line-height: 64px; |
||||
|
font-size: 32px; |
||||
|
} |
||||
|
.pos .containerlist-screen .container-picture .image-uploader { |
||||
|
position: absolute; |
||||
|
z-index: 1000; |
||||
|
top: 0; |
||||
|
left: 0; |
||||
|
right: 0; |
||||
|
bottom: 0; |
||||
|
opacity: 0; |
||||
|
cursor: pointer; |
||||
|
} |
||||
|
.pos .containerlist-screen .container-name { |
||||
|
font-size: 32px; |
||||
|
line-height: 64px; |
||||
|
margin-bottom:16px; |
||||
|
} |
||||
|
.pos .containerlist-screen .edit-buttons { |
||||
|
position: absolute; |
||||
|
right: 16px; |
||||
|
top: 10px; |
||||
|
} |
||||
|
.pos .containerlist-screen .edit-buttons .button{ |
||||
|
display: inline-block; |
||||
|
margin-left: 16px; |
||||
|
color: rgb(128,128,128); |
||||
|
cursor: pointer; |
||||
|
font-size: 36px; |
||||
|
} |
||||
|
.pos .containerlist-screen .container-details-box{ |
||||
|
position: relative; |
||||
|
font-size: 16px; |
||||
|
} |
||||
|
.pos .containerlist-screen .container-details-left{ |
||||
|
width: 50%; |
||||
|
float: left; |
||||
|
} |
||||
|
.pos .containerlist-screen .container-details-right{ |
||||
|
width: 50%; |
||||
|
float: left; |
||||
|
} |
||||
|
.pos .containerlist-screen .container-detail{ |
||||
|
line-height: 24px; |
||||
|
} |
||||
|
.pos .containerlist-screen .container-detail > .label{ |
||||
|
font-weight: bold; |
||||
|
display: inline-block; |
||||
|
width: 75px; |
||||
|
text-align: right; |
||||
|
margin-right: 8px; |
||||
|
} |
||||
|
.pos .containerlist-screen .container-details input, |
||||
|
.pos .containerlist-screen .container-details select |
||||
|
{ |
||||
|
padding: 4px; |
||||
|
border-radius: 3px; |
||||
|
border: solid 1px #cecbcb; |
||||
|
margin-bottom: 4px; |
||||
|
background: white; |
||||
|
font-family: "Lato","Lucida Grande", Helvetica, Verdana, Arial; |
||||
|
color: #555555; |
||||
|
width: 340px; |
||||
|
font-size: 14px; |
||||
|
box-sizing: border-box; |
||||
|
} |
||||
|
.pos .containerlist-screen .container-details input.container-name { |
||||
|
font-size: 24px; |
||||
|
line-height: 24px; |
||||
|
margin: 18px 6px; |
||||
|
width: 340px; |
||||
|
} |
||||
|
.pos .containerlist-screen .container-detail > .empty{ |
||||
|
opacity: 0.3; |
||||
|
} |
||||
|
.pos .containerlist-screen .searchbox{ |
||||
|
right: auto; |
||||
|
margin-left: -90px; |
||||
|
margin-top:8px; |
||||
|
left: 45%; |
||||
|
} |
||||
|
.pos .containerlist-screen .searchbox input{ |
||||
|
width: 120px; |
||||
|
} |
||||
|
.pos .containerlist-screen .button.delete-container { |
||||
|
left: 50%; |
||||
|
margin-left: 120px; |
||||
|
} |
||||
|
|
||||
|
/* Container Action buttons */ |
||||
|
.pos .control-button.main { |
||||
|
width: 75%; |
||||
|
} |
||||
|
.pos .control-button.second { |
||||
|
width: 15%; |
||||
|
flex-grow: 0; |
||||
|
} |
@ -0,0 +1,431 @@ |
|||||
|
/* |
||||
|
Copyright 2019 Coop IT Easy SCRLfs |
||||
|
Robin Keunen <robin@coopiteasy.be> |
||||
|
Pierrick Brun <pierrick.brun@akretion.com> |
||||
|
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
|
||||
|
*/ |
||||
|
|
||||
|
|
||||
|
odoo.define('pos_container.container', function (require) { |
||||
|
"use strict"; |
||||
|
|
||||
|
var models_and_db = require('pos_container.models_and_db'); |
||||
|
|
||||
|
var screens = require('point_of_sale.screens'); |
||||
|
var gui = require('point_of_sale.gui'); |
||||
|
var models = require('point_of_sale.models'); |
||||
|
|
||||
|
var core = require('web.core'); |
||||
|
var rpc = require('web.rpc'); |
||||
|
var QWeb = core.qweb; |
||||
|
var _t = core._t; |
||||
|
|
||||
|
|
||||
|
var TareButton = screens.ActionButtonWidget.extend({ |
||||
|
template: 'TareButton', |
||||
|
}); |
||||
|
|
||||
|
screens.define_action_button({ |
||||
|
'name': 'tare', |
||||
|
'widget': TareButton, |
||||
|
}); |
||||
|
|
||||
|
screens.NumpadWidget.include({ |
||||
|
// to put selected-mode on tare button outside the numpadwidget
|
||||
|
changedMode: function() { |
||||
|
this._super(); |
||||
|
if (this.state.get('mode') === 'tare'){ |
||||
|
$('.mode-button[data-mode="tare"]').addClass('selected-mode'); |
||||
|
} |
||||
|
}, |
||||
|
}); |
||||
|
|
||||
|
var ContainerButton = screens.ActionButtonWidget.extend({ |
||||
|
template: 'ContainerButton', |
||||
|
button_click: function(){ |
||||
|
this.gui.show_screen('containerlist'); |
||||
|
} |
||||
|
}); |
||||
|
|
||||
|
screens.define_action_button({ |
||||
|
'name': 'container', |
||||
|
'widget': ContainerButton, |
||||
|
}); |
||||
|
|
||||
|
var ContainerListScreenWidget = screens.ScreenWidget.extend({ |
||||
|
template: 'ContainerListScreenWidget', |
||||
|
|
||||
|
init: function(parent, options){ |
||||
|
this._super(parent, options); |
||||
|
this.container_cache = new screens.DomCache(); |
||||
|
}, |
||||
|
|
||||
|
show: function(){ |
||||
|
var self = this; |
||||
|
this._super(); |
||||
|
|
||||
|
this.renderElement(); |
||||
|
this.$('.back').click(function(){ |
||||
|
self.gui.back(); |
||||
|
}); |
||||
|
|
||||
|
this.$('.next').click(function(){ |
||||
|
self.save_changes(); |
||||
|
self.gui.show_screen('products'); |
||||
|
}); |
||||
|
|
||||
|
this.$('.delete-container').click(function(){ |
||||
|
if (self.container){ |
||||
|
self.gui.show_popup('confirm', { |
||||
|
'title': _t('Container deletion'), |
||||
|
'body': _t( |
||||
|
'Do you want to delete this container ?\n').concat( |
||||
|
self.container.name), |
||||
|
confirm: function(){ |
||||
|
self.delete_selected_container(); |
||||
|
}, |
||||
|
}); |
||||
|
} |
||||
|
}); |
||||
|
|
||||
|
var containers = this.pos.db.get_containers_sorted(1000); |
||||
|
this.render_list(containers); |
||||
|
|
||||
|
this.reload_containers(); |
||||
|
|
||||
|
this.$('.container-list-contents').delegate('.container-line', |
||||
|
'click', function(event){ |
||||
|
self.line_select(event,$(this),$(this).data('id')); |
||||
|
}); |
||||
|
|
||||
|
var search_timeout = null; |
||||
|
|
||||
|
if(this.pos.config.iface_vkeyboard && this.chrome.widget.keyboard){ |
||||
|
this.chrome.widget.keyboard.connect( |
||||
|
this.$('.searchbox input') |
||||
|
); |
||||
|
} |
||||
|
|
||||
|
this.$('.searchbox input').on('keyup',function(event){ |
||||
|
clearTimeout(search_timeout); |
||||
|
|
||||
|
var query = this.value; |
||||
|
|
||||
|
search_timeout = setTimeout(function(){ |
||||
|
self.perform_search(query,event.which === 13); |
||||
|
},70); |
||||
|
}); |
||||
|
|
||||
|
this.$('.searchbox .search-clear').click(function(){ |
||||
|
self.clear_search(); |
||||
|
}); |
||||
|
}, |
||||
|
delete_selected_container: function(){ |
||||
|
var self = this; |
||||
|
|
||||
|
if (!self.container.id){ |
||||
|
self.deleted_container(self.container.barcode) |
||||
|
} |
||||
|
else { |
||||
|
rpc.query({ |
||||
|
model: 'pos.container', |
||||
|
method: 'unlink', |
||||
|
args: [self.container.id], |
||||
|
}).then(function(){ |
||||
|
self.deleted_container(self.container.barcode); |
||||
|
},function(err,ev){ |
||||
|
ev.preventDefault(); |
||||
|
var error_body = _t('Your Internet connection is probably down.'); |
||||
|
if (err.data) { |
||||
|
var except = err.data; |
||||
|
error_body = except.arguments && except.arguments[0] || except.message || error_body; |
||||
|
} |
||||
|
self.gui.show_popup('error',{ |
||||
|
'title': _t('Error: Could not Save Changes'), |
||||
|
'body': error_body, |
||||
|
}); |
||||
|
} |
||||
|
); |
||||
|
} |
||||
|
}, |
||||
|
deleted_container: function(barcode){ |
||||
|
var self = this; |
||||
|
this.pos.db.remove_containers([barcode]); |
||||
|
this.$('.container-list .highlight').remove(); |
||||
|
this.container = null; |
||||
|
}, |
||||
|
perform_search: function(query, associate_result){ |
||||
|
if(query){ |
||||
|
var containers = this.pos.db.search_container(query); |
||||
|
if ( associate_result && containers.length === 1){ |
||||
|
this.container = containers[0]; |
||||
|
this.save_changes(); |
||||
|
this.gui.back(); |
||||
|
} |
||||
|
this.render_list(containers); |
||||
|
}else{ |
||||
|
var containers = this.pos.db.get_containers_sorted(); |
||||
|
this.render_list(containers); |
||||
|
} |
||||
|
}, |
||||
|
clear_search: function(){ |
||||
|
var containers = this.pos.db.get_containers_sorted(1000); |
||||
|
this.render_list(containers); |
||||
|
this.$('.searchbox input')[0].value = ''; |
||||
|
this.$('.searchbox input').focus(); |
||||
|
}, |
||||
|
render_list: function(containers) { |
||||
|
var contents = this.$el[0].querySelector('.container-list-contents'); |
||||
|
contents.innerHTML = ""; |
||||
|
for(var i = 0, len = Math.min(containers.length,1000); i < len; i++){ |
||||
|
var container = containers[i]; |
||||
|
var containerline_html = QWeb.render('ContainerLine',{widget: this, container:containers[i]}); |
||||
|
var containerline = document.createElement('tbody'); |
||||
|
containerline.innerHTML = containerline_html; |
||||
|
containerline = containerline.childNodes[1]; |
||||
|
|
||||
|
if(containers === this.container) { |
||||
|
containerline.classList.add('highlight'); |
||||
|
} else { |
||||
|
containerline.classList.remove('highlight'); |
||||
|
} |
||||
|
|
||||
|
contents.appendChild(containerline); |
||||
|
} |
||||
|
}, |
||||
|
save_changes: function(){ |
||||
|
this.pos.get_order().add_container(this.container); |
||||
|
}, |
||||
|
toggle_delete_button: function(){ |
||||
|
var $button = this.$('.button.delete-container'); |
||||
|
$button.toggleClass('oe_hidden', !this.container); |
||||
|
}, |
||||
|
toggle_save_button: function(){ |
||||
|
var $button = this.$('.button.next'); |
||||
|
if (this.container) { |
||||
|
$button.text('Set Container'); |
||||
|
} |
||||
|
$button.toggleClass('oe_hidden', !this.container); |
||||
|
}, |
||||
|
line_select: function(event,$line,barcode){ |
||||
|
var container = this.pos.db.get_container_by_barcode(barcode); |
||||
|
this.$('.container-list .lowlight').removeClass('lowlight'); |
||||
|
if ( $line.hasClass('highlight') ){ |
||||
|
$line.removeClass('highlight'); |
||||
|
$line.addClass('lowlight'); |
||||
|
this.toggle_delete_button(); |
||||
|
this.toggle_save_button(); |
||||
|
}else{ |
||||
|
this.$('.container-list .highlight').removeClass('highlight'); |
||||
|
$line.addClass('highlight'); |
||||
|
var y = event.pageY - $line.parent().offset().top; |
||||
|
this.container = container; |
||||
|
this.toggle_delete_button(); |
||||
|
this.toggle_save_button(); |
||||
|
} |
||||
|
}, |
||||
|
|
||||
|
// This fetches container changes on the server, and in case of changes,
|
||||
|
// rerenders the affected views
|
||||
|
reload_containers: function(){ |
||||
|
var self = this; |
||||
|
return this.pos.load_new_containers().then(function(){ |
||||
|
// containers may have changed in the backend
|
||||
|
self.container_cache = new screens.DomCache(); |
||||
|
|
||||
|
self.render_list(self.pos.db.get_containers_sorted(1000)); |
||||
|
|
||||
|
var last_orderline = self.pos.get_order().get_last_orderline(); |
||||
|
|
||||
|
if(last_orderline) { |
||||
|
// update the currently assigned container if it has been changed in db.
|
||||
|
var curr_container = last_orderline.get_container(); |
||||
|
} |
||||
|
|
||||
|
if (curr_container) { |
||||
|
last_orderline.set_container( |
||||
|
self.pos.db.get_container_by_barcode(curr_container.barcode)); |
||||
|
} |
||||
|
}); |
||||
|
}, |
||||
|
|
||||
|
close: function(){ |
||||
|
this._super(); |
||||
|
if (this.pos.config.iface_vkeyboard && this.chrome.widget.keyboard) { |
||||
|
this.chrome.widget.keyboard.hide(); |
||||
|
} |
||||
|
}, |
||||
|
|
||||
|
auto_back: true, |
||||
|
}); |
||||
|
|
||||
|
gui.define_screen({ |
||||
|
name:'containerlist', |
||||
|
widget: ContainerListScreenWidget |
||||
|
}); |
||||
|
|
||||
|
// add container barcode scan
|
||||
|
screens.ScreenWidget.include({ |
||||
|
barcode_container_action: function(code){ |
||||
|
var self = this; |
||||
|
if (self.pos.scan_container(code)) { |
||||
|
// nothing to do now, the container is added
|
||||
|
// as an orderline if found.
|
||||
|
} else { |
||||
|
self.gui.show_screen('containerscale', {barcode: code.base_code}); |
||||
|
} |
||||
|
}, |
||||
|
show: function(){ |
||||
|
var self = this; |
||||
|
this._super(); |
||||
|
this.pos.barcode_reader.set_action_callback({ |
||||
|
'container': _.bind(self.barcode_container_action, self), |
||||
|
}); |
||||
|
}, |
||||
|
}); |
||||
|
|
||||
|
screens.ProductScreenWidget.include({ |
||||
|
// to use Tare Button from outside the NumpadWidget
|
||||
|
start: function(){ |
||||
|
this._super(); |
||||
|
var tare_button = $('.mode-button[data-mode="tare"]'); |
||||
|
tare_button.click(_.bind(this.numpad.clickChangeMode, this.numpad)); |
||||
|
}, |
||||
|
// to add a product to a container orderline
|
||||
|
click_product: function(product) { |
||||
|
var order = this.pos.get_order(); |
||||
|
var selected_orderline = order.get_selected_orderline(); |
||||
|
if (product.to_weight && selected_orderline && |
||||
|
selected_orderline.product === this.pos.get_container_product()){ |
||||
|
var container = selected_orderline.get_container(); |
||||
|
this.gui.show_screen( |
||||
|
'scale', |
||||
|
{product: product, |
||||
|
container: container, |
||||
|
old_orderline: selected_orderline}); |
||||
|
} else { |
||||
|
this._super(product); |
||||
|
} |
||||
|
}, |
||||
|
}); |
||||
|
|
||||
|
screens.ScaleScreenWidget.include({ |
||||
|
order_product: function(){ |
||||
|
// Replace the orderline if the product is the placeholder
|
||||
|
// container product.
|
||||
|
var container = this.gui.get_current_screen_param('container'); |
||||
|
if (container){ |
||||
|
var order = this.pos.get_order(); |
||||
|
order.add_product(this.get_product(),{ quantity: this.weight, price: this.price }); |
||||
|
var orderline = order.get_selected_orderline(); |
||||
|
orderline.set_container(container); |
||||
|
var old_orderline = this.gui.get_current_screen_param( |
||||
|
'old_orderline'); |
||||
|
if (old_orderline){ |
||||
|
order.remove_orderline(old_orderline); |
||||
|
} |
||||
|
orderline.set_quantity(this.weight); |
||||
|
orderline.set_gross_weight(this.weight + container.weight); |
||||
|
orderline.set_tare_mode('AUTO'); |
||||
|
orderline.trigger('change', orderline); |
||||
|
} else { |
||||
|
this._super(); |
||||
|
var orderline = this.pos.get_order().get_selected_orderline(); |
||||
|
orderline.set_tare_mode('AUTO'); |
||||
|
} |
||||
|
}, |
||||
|
}); |
||||
|
|
||||
|
var ContainerScaleScreenWidget = screens.ScaleScreenWidget.extend({ |
||||
|
template: 'ContainerScaleScreenWidget', |
||||
|
|
||||
|
next_screen: 'products', |
||||
|
previous_screen: 'products', |
||||
|
|
||||
|
init: function(parent, options){ |
||||
|
this._super(parent, options); |
||||
|
}, |
||||
|
|
||||
|
show: function(){ |
||||
|
this._super(); |
||||
|
var self = this; |
||||
|
|
||||
|
this.$('.next,.add-container').click(function(){ |
||||
|
self.create_container(); |
||||
|
}); |
||||
|
|
||||
|
if(this.pos.config.iface_vkeyboard && this.chrome.widget.keyboard){ |
||||
|
this.chrome.widget.keyboard.connect($(this.el.querySelector('.container-name input'))); |
||||
|
} |
||||
|
}, |
||||
|
get_product: function(){ |
||||
|
return this.pos.get_container_product(); |
||||
|
}, |
||||
|
create_container: function(){ |
||||
|
var self = this; |
||||
|
var fields = {}; |
||||
|
|
||||
|
fields['weight'] = this.weight; |
||||
|
|
||||
|
this.$('.container-name .detail').each(function(idx,el){ |
||||
|
fields['name'] = el.value; |
||||
|
|
||||
|
}); |
||||
|
|
||||
|
fields.barcode = this.gui.get_current_screen_param('barcode') || false; |
||||
|
fields.name = fields.name || _t('Container'); |
||||
|
|
||||
|
this.pos.push_container(fields).then( |
||||
|
this.pushed_container(fields["barcode"]) |
||||
|
); |
||||
|
}, |
||||
|
pushed_container: function(barcode){ |
||||
|
var self = this; |
||||
|
self.gui.show_screen(self.next_screen); |
||||
|
}, |
||||
|
close: function(){ |
||||
|
this._super(); |
||||
|
if (this.pos.config.iface_vkeyboard && this.chrome.widget.keyboard) { |
||||
|
this.chrome.widget.keyboard.hide(); |
||||
|
} |
||||
|
}, |
||||
|
}); |
||||
|
|
||||
|
gui.define_screen({ |
||||
|
name:'containerscale', |
||||
|
widget: ContainerScaleScreenWidget, |
||||
|
}); |
||||
|
|
||||
|
screens.ProductListWidget.include({ |
||||
|
render_product: function(product){ |
||||
|
if(product.barcode != 'CONTAINER'){ |
||||
|
return this._super(product); |
||||
|
} else { |
||||
|
return document.createElement('div'); |
||||
|
} |
||||
|
} |
||||
|
}); |
||||
|
|
||||
|
screens.OrderWidget.include({ |
||||
|
set_value: function(val) { |
||||
|
this._super(val); |
||||
|
var order = this.pos.get_order(); |
||||
|
if (order.get_selected_orderline()) { |
||||
|
var oline = order.get_selected_orderline(); |
||||
|
var mode = this.numpad_state.get('mode'); |
||||
|
if( mode === 'tare'){ |
||||
|
oline.set_tare(val); |
||||
|
} |
||||
|
if( mode === 'quantity' && oline.container) { |
||||
|
oline.set_gross_weight(parseFloat(val) + oline.container.weight); |
||||
|
} |
||||
|
oline.set_tare_mode('MAN'); |
||||
|
} |
||||
|
}, |
||||
|
}); |
||||
|
|
||||
|
return { |
||||
|
ContainerScaleScreenWidget: ContainerScaleScreenWidget, |
||||
|
}; |
||||
|
|
||||
|
}); |
@ -0,0 +1,619 @@ |
|||||
|
/* |
||||
|
Copyright 2019 Coop IT Easy SCRLfs |
||||
|
Pierrick Brun <pierrick.brun@akretion.com> |
||||
|
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
|
||||
|
*/ |
||||
|
|
||||
|
|
||||
|
odoo.define('pos_container.models_and_db', function (require) { |
||||
|
"use strict"; |
||||
|
|
||||
|
var PosDB = require('point_of_sale.DB'); |
||||
|
var models = require('point_of_sale.models'); |
||||
|
var rpc = require('web.rpc'); |
||||
|
var config = require('web.config'); |
||||
|
|
||||
|
var core = require('web.core'); |
||||
|
var QWeb = core.qweb; |
||||
|
|
||||
|
var utils = require('web.utils'); |
||||
|
var field_utils = require('web.field_utils'); |
||||
|
var round_di = utils.round_decimals; |
||||
|
var round_pr = utils.round_precision; |
||||
|
|
||||
|
// include not available => extend
|
||||
|
models.PosModel = models.PosModel.extend({ |
||||
|
get_container_product: function(){ |
||||
|
// assign value if not already assigned.
|
||||
|
// Avoids rewriting init function
|
||||
|
if (!this.container_product){ |
||||
|
this.container_product = this.db.get_product_by_barcode( |
||||
|
'CONTAINER'); |
||||
|
} |
||||
|
return this.container_product |
||||
|
}, |
||||
|
scan_container: function(parsed_code){ |
||||
|
var selected_order = this.get_order(); |
||||
|
var container = this.db.get_container_by_barcode( |
||||
|
parsed_code.base_code); |
||||
|
|
||||
|
if(!container){ |
||||
|
return false; |
||||
|
} |
||||
|
|
||||
|
selected_order.add_container(container); |
||||
|
return true; |
||||
|
}, |
||||
|
// reload the list of container, returns as a deferred that resolves if there were
|
||||
|
// updated containers, and fails if not
|
||||
|
load_new_containers: function(){ |
||||
|
var self = this; |
||||
|
var def = new $.Deferred(); |
||||
|
var fields = _.find(this.models,function(model){ |
||||
|
return model.model === 'pos.container'; |
||||
|
}).fields; |
||||
|
var domain = []; |
||||
|
rpc.query({ |
||||
|
model: 'pos.container', |
||||
|
method: 'search_read', |
||||
|
args: [domain, fields], |
||||
|
}, { |
||||
|
timeout: 3000, |
||||
|
shadow: true, |
||||
|
}) |
||||
|
.then(function(containers){ |
||||
|
if (self.db.add_containers(containers)) { |
||||
|
// check if the partners we got were real updates
|
||||
|
def.resolve(); |
||||
|
} else { |
||||
|
def.reject(); |
||||
|
} |
||||
|
}, function(type,err){ def.reject(); }); |
||||
|
return def; |
||||
|
}, |
||||
|
// load placeholder product for containers.
|
||||
|
// it is done here to load it even if inactivated.
|
||||
|
load_placeholder_product: function(){ |
||||
|
var self = this; |
||||
|
var fields = _.find(this.models,function(model){ |
||||
|
return model.model === 'product.product'; |
||||
|
}).fields; |
||||
|
var domain = [['barcode', '=', 'CONTAINER'], ['active', '=', false]]; |
||||
|
// no need to load it when active because it is already done in standard
|
||||
|
return rpc.query({ |
||||
|
model: 'product.product', |
||||
|
method: 'search_read', |
||||
|
args: [domain, fields], |
||||
|
}).then(function(products){ |
||||
|
self.db.add_products(_.map(products, function (product) { |
||||
|
return new models.Product({}, product); |
||||
|
})); |
||||
|
}); |
||||
|
}, |
||||
|
|
||||
|
// saves the container locally and try to send it to the backend.
|
||||
|
// it returns a deferred that succeeds after having tried to send the container and all the other pending containers.
|
||||
|
push_container: function(container, opts) { |
||||
|
opts = opts || {}; |
||||
|
var self = this; |
||||
|
|
||||
|
if(container){ |
||||
|
this.db.add_containers([container]); |
||||
|
} |
||||
|
|
||||
|
var pushed = new $.Deferred(); |
||||
|
|
||||
|
this.flush_mutex.exec(function(){ |
||||
|
var flushed = self._save_containers_to_server(self.db.get_containers_sorted(), opts); |
||||
|
|
||||
|
flushed.always(function(ids){ |
||||
|
pushed.resolve(); |
||||
|
}); |
||||
|
|
||||
|
return flushed; |
||||
|
}); |
||||
|
return pushed; |
||||
|
}, |
||||
|
|
||||
|
// send an array of containers to the server
|
||||
|
// available options:
|
||||
|
// - timeout: timeout for the rpc call in ms
|
||||
|
// returns a deferred that resolves with the list of
|
||||
|
// server generated ids for the sent containers
|
||||
|
_save_containers_to_server: function (containers, options) { |
||||
|
var self = this; |
||||
|
var containers= containers.filter(container => !( "id" in container)) |
||||
|
if (!containers || !containers.length) { |
||||
|
var result = $.Deferred(); |
||||
|
result.resolve([]); |
||||
|
return result; |
||||
|
} |
||||
|
|
||||
|
options = options || {}; |
||||
|
var timeout = typeof options.timeout === 'number' ? options.timeout : 7500 * containers.length; |
||||
|
|
||||
|
return rpc.query({ |
||||
|
model: 'pos.container', |
||||
|
method: 'create_from_ui', |
||||
|
args: containers, |
||||
|
}, { |
||||
|
timeout: timeout, |
||||
|
}) |
||||
|
.then(function (server_ids) { |
||||
|
//self.db.remove_containers(containers);
|
||||
|
_.each(containers, function(container, key){ |
||||
|
container["id"] = server_ids[key] |
||||
|
}); |
||||
|
//self.db.add_containers(containers)
|
||||
|
self.set('failed',false); |
||||
|
return server_ids; |
||||
|
}).fail(function (type, error){ |
||||
|
if(error.code === 200 ){ // Business Logic Error, not a connection problem
|
||||
|
//if warning do not need to display traceback!!
|
||||
|
if (error.data.exception_type == 'warning') { |
||||
|
delete error.data.debug; |
||||
|
} |
||||
|
|
||||
|
// Hide error if already shown before ...
|
||||
|
if ((!self.get('failed') || options.show_error) && !options.to_invoice) { |
||||
|
self.gui.show_popup('error-traceback',{ |
||||
|
'title': error.data.message, |
||||
|
'body': error.data.debug |
||||
|
}); |
||||
|
} |
||||
|
self.set('failed',error); |
||||
|
} |
||||
|
console.error('Failed to send containers:', containers); |
||||
|
}); |
||||
|
}, |
||||
|
|
||||
|
// wrapper around the _save_to_server that updates the synch status widget
|
||||
|
// it is modified to send containers before orders
|
||||
|
_flush_orders: function(orders, options) { |
||||
|
var self = this; |
||||
|
this.set('synch',{ state: 'connecting', pending: orders.length}); |
||||
|
|
||||
|
return self._save_containers_to_server(self.db.get_containers_sorted()) |
||||
|
.then(function(container_ids) { |
||||
|
for (var i=0; i < orders.length; i++){ |
||||
|
if (orders[i].data.lines) { |
||||
|
for (var j=0; j < orders[i].data.lines[0].length; j++){ |
||||
|
var orderline = orders[i].data.lines[0][j] |
||||
|
if ( !orderline.container_id && orderline.container_barcode) { |
||||
|
orderline.container_id = self.db.get_container_by_barcode(orderline.container_barcode).id; |
||||
|
delete orderline["container_barcode"] |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
return self._save_to_server(orders, options) |
||||
|
}).done(function (server_ids) { |
||||
|
var pending = self.db.get_orders().length; |
||||
|
|
||||
|
self.set('synch', { |
||||
|
state: pending ? 'connecting' : 'connected', |
||||
|
pending: pending |
||||
|
}); |
||||
|
|
||||
|
return server_ids; |
||||
|
}).fail(function(error, event){ |
||||
|
var pending = self.db.get_orders().length; |
||||
|
if (self.get('failed')) { |
||||
|
self.set('synch', { state: 'error', pending: pending }); |
||||
|
} else { |
||||
|
self.set('synch', { state: 'disconnected', pending: pending }); |
||||
|
} |
||||
|
}); |
||||
|
}, |
||||
|
}); |
||||
|
|
||||
|
models.Order = models.Order.extend({ |
||||
|
add_container: function(container, options){ |
||||
|
if(this._printed){ |
||||
|
this.destroy(); |
||||
|
return this.pos.get_order().add_container(container, options); |
||||
|
} |
||||
|
options = options || {}; |
||||
|
var attr = JSON.parse(JSON.stringify(container)); |
||||
|
attr.pos = this.pos; |
||||
|
attr.order = this; |
||||
|
var product = this.pos.get_container_product(); |
||||
|
var line = new models.Orderline({}, { |
||||
|
pos: this.pos, order: this, product: product}); |
||||
|
|
||||
|
line.set_container(container); |
||||
|
line.set_quantity(0); |
||||
|
this.orderlines.add(line); |
||||
|
|
||||
|
this.select_orderline(this.get_last_orderline()); |
||||
|
}, |
||||
|
has_tare_line: function(mode){ |
||||
|
var orderlines = this.orderlines.models |
||||
|
for(var i=0; i < orderlines.length; i++){ |
||||
|
var line = orderlines[i]; |
||||
|
if(line && line.get_tare_mode() === mode){ |
||||
|
return true; |
||||
|
} |
||||
|
} |
||||
|
return false; |
||||
|
}, |
||||
|
export_for_printing: function(){ |
||||
|
var orderlines = []; |
||||
|
var self = this; |
||||
|
|
||||
|
this.orderlines.each(function(orderline){ |
||||
|
orderlines.push(orderline.export_for_printing()); |
||||
|
}); |
||||
|
|
||||
|
var paymentlines = []; |
||||
|
this.paymentlines.each(function(paymentline){ |
||||
|
paymentlines.push(paymentline.export_for_printing()); |
||||
|
}); |
||||
|
var client = this.get('client'); |
||||
|
var cashier = this.pos.get_cashier(); |
||||
|
var company = this.pos.company; |
||||
|
var shop = this.pos.shop; |
||||
|
var date = new Date(); |
||||
|
|
||||
|
function is_xml(subreceipt){ |
||||
|
return subreceipt ? (subreceipt.split('\n')[0].indexOf('<!DOCTYPE QWEB') >= 0) : false; |
||||
|
} |
||||
|
|
||||
|
function render_xml(subreceipt){ |
||||
|
if (!is_xml(subreceipt)) { |
||||
|
return subreceipt; |
||||
|
} else { |
||||
|
subreceipt = subreceipt.split('\n').slice(1).join('\n'); |
||||
|
var qweb = new QWeb2.Engine(); |
||||
|
qweb.debug = config.debug; |
||||
|
qweb.default_dict = _.clone(QWeb.default_dict); |
||||
|
qweb.add_template('<templates><t t-name="subreceipt">'+subreceipt+'</t></templates>'); |
||||
|
|
||||
|
return qweb.render('subreceipt',{'pos':self.pos,'widget':self.pos.chrome,'order':self, 'receipt': receipt}) ; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
var receipt = { |
||||
|
orderlines: orderlines, |
||||
|
paymentlines: paymentlines, |
||||
|
subtotal: this.get_subtotal(), |
||||
|
total_with_tax: this.get_total_with_tax(), |
||||
|
total_without_tax: this.get_total_without_tax(), |
||||
|
total_tax: this.get_total_tax(), |
||||
|
total_paid: this.get_total_paid(), |
||||
|
total_discount: this.get_total_discount(), |
||||
|
tax_details: this.get_tax_details(), |
||||
|
change: this.get_change(), |
||||
|
name : this.get_name(), |
||||
|
client: client ? client.name : null , |
||||
|
invoice_id: null, //TODO
|
||||
|
cashier: cashier ? cashier.name : null, |
||||
|
precision: { |
||||
|
price: 2, |
||||
|
money: 2, |
||||
|
quantity: 3, |
||||
|
}, |
||||
|
date: { |
||||
|
year: date.getFullYear(), |
||||
|
month: date.getMonth(), |
||||
|
date: date.getDate(), // day of the month
|
||||
|
day: date.getDay(), // day of the week
|
||||
|
hour: date.getHours(), |
||||
|
minute: date.getMinutes() , |
||||
|
isostring: date.toISOString(), |
||||
|
localestring: date.toLocaleString(), |
||||
|
}, |
||||
|
company:{ |
||||
|
email: company.email, |
||||
|
website: company.website, |
||||
|
company_registry: company.company_registry, |
||||
|
contact_address: company.partner_id[1], |
||||
|
vat: company.vat, |
||||
|
vat_label: company.country && company.country.vat_label || '', |
||||
|
name: company.name, |
||||
|
phone: company.phone, |
||||
|
logo: this.pos.company_logo_base64, |
||||
|
}, |
||||
|
shop:{ |
||||
|
name: shop.name, |
||||
|
}, |
||||
|
currency: this.pos.currency, |
||||
|
//custom here
|
||||
|
has_tare_mode: { |
||||
|
auto: this.has_tare_line('AUTO'), |
||||
|
manual: this.has_tare_line('MAN'), |
||||
|
} |
||||
|
//custom end
|
||||
|
}; |
||||
|
|
||||
|
if (is_xml(this.pos.config.receipt_header)){ |
||||
|
receipt.header = ''; |
||||
|
receipt.header_xml = render_xml(this.pos.config.receipt_header); |
||||
|
} else { |
||||
|
receipt.header = this.pos.config.receipt_header || ''; |
||||
|
} |
||||
|
|
||||
|
if (is_xml(this.pos.config.receipt_footer)){ |
||||
|
receipt.footer = ''; |
||||
|
receipt.footer_xml = render_xml(this.pos.config.receipt_footer); |
||||
|
} else { |
||||
|
receipt.footer = this.pos.config.receipt_footer || ''; |
||||
|
} |
||||
|
|
||||
|
return receipt; |
||||
|
}, |
||||
|
}); |
||||
|
|
||||
|
// Add container to order line
|
||||
|
models.Orderline = models.Orderline.extend({ |
||||
|
get_container: function(){ |
||||
|
return this.container; |
||||
|
}, |
||||
|
set_container: function(container){ |
||||
|
this.container = container; |
||||
|
}, |
||||
|
set_tare_mode: function(mode){ |
||||
|
if (['MAN', 'AUTO'].indexOf(mode) != -1){ |
||||
|
this.tare_mode = mode; |
||||
|
this.trigger('change', this); |
||||
|
} |
||||
|
}, |
||||
|
get_tare_mode: function() { |
||||
|
return this.tare_mode; |
||||
|
}, |
||||
|
set_tare: function(tare){ |
||||
|
this.tare = this.get_value_rounded(tare).toFixed(3); |
||||
|
this.container = null; |
||||
|
if (this.gross_weight && this.gross_weight != 'NaN'){ |
||||
|
this.set_quantity(this.gross_weight - parseFloat(this.tare)); |
||||
|
} |
||||
|
else{ |
||||
|
this.set_gross_weight(this.quantity); |
||||
|
this.set_quantity(this.quantity - parseFloat(this.tare)); |
||||
|
} |
||||
|
this.trigger('change', this); |
||||
|
}, |
||||
|
get_tare: function(){ |
||||
|
return this.tare || 0; |
||||
|
}, |
||||
|
get_gross_weight: function(){ |
||||
|
return this.gross_weight; |
||||
|
}, |
||||
|
set_gross_weight: function(weight){ |
||||
|
this.gross_weight = this.get_value_rounded(weight).toFixed(3); |
||||
|
this.trigger('change', this); |
||||
|
}, |
||||
|
set_quantity: function(quantity, keep_price){ |
||||
|
// copied from odoo core
|
||||
|
this.order.assert_editable(); |
||||
|
if(quantity === 'remove'){ |
||||
|
this.order.remove_orderline(this); |
||||
|
return; |
||||
|
}else{ |
||||
|
var quant = parseFloat(quantity) || 0; |
||||
|
var unit = this.get_unit(); |
||||
|
if(unit){ |
||||
|
if (unit.rounding) { |
||||
|
this.quantity = round_pr(quant, unit.rounding); |
||||
|
var decimals = this.pos.dp['Product Unit of Measure']; |
||||
|
this.quantity = round_di(this.quantity, decimals) |
||||
|
this.quantityStr = field_utils.format.float(this.quantity, {digits: [69, decimals]}); |
||||
|
} else { |
||||
|
this.quantity = round_pr(quant, 1); |
||||
|
this.quantityStr = this.quantity.toFixed(0); |
||||
|
} |
||||
|
}else{ |
||||
|
this.quantity = quant; |
||||
|
this.quantityStr = '' + this.quantity; |
||||
|
} |
||||
|
} |
||||
|
// just like in sale.order changing the quantity will recompute the unit price
|
||||
|
if(! keep_price && ! this.price_manually_set){ |
||||
|
this.set_unit_price(this.product.get_price(this.order.pricelist, this.get_quantity())); |
||||
|
this.order.fix_tax_included_price(this); |
||||
|
} |
||||
|
|
||||
|
// surcharge starts here
|
||||
|
if (this.tare){ |
||||
|
this.set_gross_weight(this.quantity + parseFloat(this.tare)); |
||||
|
} |
||||
|
this.trigger('change', this); |
||||
|
}, |
||||
|
get_value_rounded: function(value){ |
||||
|
var value = parseFloat(value) || 0; |
||||
|
var unit = this.get_unit(); |
||||
|
if(unit){ |
||||
|
if (unit.rounding) { |
||||
|
value = round_pr(value, unit.rounding); |
||||
|
var decimals = this.pos.dp['Product Unit of Measure']; |
||||
|
value = round_di(value, decimals) |
||||
|
} else { |
||||
|
value = round_pr(value, 1); |
||||
|
} |
||||
|
} |
||||
|
return value; |
||||
|
}, |
||||
|
export_as_JSON: function(){ |
||||
|
var pack_lot_ids = []; |
||||
|
if (this.has_product_lot){ |
||||
|
this.pack_lot_lines.each(_.bind( function(item) { |
||||
|
return pack_lot_ids.push([0, 0, item.export_as_JSON()]); |
||||
|
}, this)); |
||||
|
} |
||||
|
return { |
||||
|
qty: this.get_quantity(), |
||||
|
price_unit: this.get_unit_price(), |
||||
|
price_subtotal: this.get_price_without_tax(), |
||||
|
price_subtotal_incl: this.get_price_with_tax(), |
||||
|
discount: this.get_discount(), |
||||
|
product_id: this.get_product().id, |
||||
|
tax_ids: [[6, false, _.map(this.get_applicable_taxes(), function(tax){ return tax.id; })]], |
||||
|
id: this.id, |
||||
|
pack_lot_ids: pack_lot_ids, |
||||
|
//custom starts here
|
||||
|
tare: this.get_tare() ? this.get_tare() : null, |
||||
|
container_id: this.get_container() ? this.get_container().id : null, |
||||
|
container_barcode: this.get_container() ? this.get_container().barcode : null, |
||||
|
container_weight: this.get_container() ? this.get_container().weight : null, |
||||
|
}; |
||||
|
}, |
||||
|
//used to create a json of the ticket, to be sent to the printer
|
||||
|
export_for_printing: function(){ |
||||
|
return { |
||||
|
quantity: this.get_quantity(), |
||||
|
unit_name: this.get_unit().name, |
||||
|
price: this.get_unit_price(), |
||||
|
discount: this.get_discount(), |
||||
|
product_name: this.get_product().display_name, |
||||
|
product_name_wrapped: this.generate_wrapped_product_name(), |
||||
|
price_display : this.get_display_price(), |
||||
|
price_with_tax : this.get_price_with_tax(), |
||||
|
price_without_tax: this.get_price_without_tax(), |
||||
|
tax: this.get_tax(), |
||||
|
product_description: this.get_product().description, |
||||
|
product_description_sale: this.get_product().description_sale, |
||||
|
// extension starts here
|
||||
|
container: this.get_container(), |
||||
|
tare: this.get_tare(), |
||||
|
tare_mode: this.get_tare_mode(), |
||||
|
gross_weight: this.get_gross_weight(), |
||||
|
product_barcode: this.get_product().barcode, |
||||
|
}; |
||||
|
}, |
||||
|
}); |
||||
|
|
||||
|
PosDB.include({ |
||||
|
init: function(parent, options) { |
||||
|
this._super(parent, options); |
||||
|
|
||||
|
this.container_sorted = []; |
||||
|
this.container_by_id = {}; |
||||
|
this.container_by_barcode = {}; |
||||
|
this.container_search_string = ""; |
||||
|
this.container_write_date = null; |
||||
|
}, |
||||
|
_container_search_string: function(container){ |
||||
|
|
||||
|
var str = ''; |
||||
|
|
||||
|
if(container.barcode){ |
||||
|
str += '|' + container.barcode; |
||||
|
} |
||||
|
if(container.name) { |
||||
|
str += '|' + container.name; |
||||
|
} |
||||
|
var id = container.id || 0; |
||||
|
str = '' + id + ':' + str.replace(':','') + '\n'; |
||||
|
|
||||
|
return str; |
||||
|
}, |
||||
|
add_containers: function(containers) { |
||||
|
var updated_count = 0; |
||||
|
var new_write_date = ''; |
||||
|
for(var i = 0, len = containers.length; i < len; i++) { |
||||
|
var container = containers[i]; |
||||
|
|
||||
|
if (this.container_write_date && |
||||
|
this.container_by_barcode[container.barcode] && |
||||
|
new Date(this.container_write_date).getTime() + 1000 >= |
||||
|
new Date(container.write_date).getTime() ) { |
||||
|
// FIXME: The write_date is stored with milisec precision in the database
|
||||
|
// but the dates we get back are only precise to the second. This means when
|
||||
|
// you read containers modified strictly after time X, you get back containers that were
|
||||
|
// modified X - 1 sec ago.
|
||||
|
continue; |
||||
|
} else if ( new_write_date < container.write_date ) { |
||||
|
new_write_date = container.write_date; |
||||
|
} |
||||
|
if (!this.container_by_barcode[container.barcode]) { |
||||
|
this.container_sorted.push(container.barcode); |
||||
|
} |
||||
|
this.container_by_barcode[container.barcode] = container; |
||||
|
|
||||
|
updated_count += 1; |
||||
|
} |
||||
|
|
||||
|
this.container_write_date = new_write_date || this.container_write_date; |
||||
|
|
||||
|
if (updated_count) { |
||||
|
// If there were updates, we need to completely
|
||||
|
// rebuild the search string and the id indexing
|
||||
|
|
||||
|
this.container_search_string = ""; |
||||
|
this.container_by_id = {}; |
||||
|
|
||||
|
for (var barcode in this.container_by_barcode) { |
||||
|
var container = this.container_by_barcode[barcode]; |
||||
|
|
||||
|
if(container.id){ |
||||
|
this.container_by_id[container.id] = container; |
||||
|
} |
||||
|
this.container_search_string += this._container_search_string(container); |
||||
|
} |
||||
|
} |
||||
|
return updated_count; |
||||
|
}, |
||||
|
remove_containers: function(barcodes){ |
||||
|
for(var i = 0; i < barcodes.length; i++) { |
||||
|
var container = this.container_by_barcode[barcodes[i]]; |
||||
|
if (container){ |
||||
|
var index_s = this.container_sorted.indexOf(container.barcode); |
||||
|
this.container_sorted.splice(index_s, 1); |
||||
|
delete this.container_by_id[container.id]; |
||||
|
delete this.container_by_barcode[container.barcode]; |
||||
|
} |
||||
|
} |
||||
|
}, |
||||
|
get_container_write_date: function(){ |
||||
|
return this.container_write_date; |
||||
|
}, |
||||
|
get_container_by_id: function(id){ |
||||
|
return this.container_by_id[id]; |
||||
|
}, |
||||
|
get_container_by_barcode: function(barcode){ |
||||
|
return this.container_by_barcode[barcode]; |
||||
|
}, |
||||
|
get_containers_sorted: function(max_count){ |
||||
|
max_count = max_count ? Math.min(this.container_sorted.length, max_count) : this.container_sorted.length; |
||||
|
var containers = []; |
||||
|
for (var i = 0; i < max_count; i++) { |
||||
|
containers.push(this.container_by_barcode[this.container_sorted[i]]); |
||||
|
} |
||||
|
|
||||
|
return containers; |
||||
|
}, |
||||
|
search_container: function(query) { |
||||
|
try { |
||||
|
query = query.replace(/[\[\]\(\)\+\*\?\.\-\!\&\^\$\|\~\_\{\}\:\,\\\/]/g,'.'); |
||||
|
query = query.replace(' ','.+'); |
||||
|
var re = RegExp("([0-9]+):\\|([0-9]*"+query+"[0-9]*\\|\|[0-9]*\\|.*?"+query+")","gi"); |
||||
|
} catch(e) { |
||||
|
return []; |
||||
|
} |
||||
|
var results = []; |
||||
|
for(var i = 0; i < this.limit; i++) { |
||||
|
var r = re.exec(this.container_search_string); |
||||
|
if(r) { |
||||
|
// r[1] = id, r[2] = barcode
|
||||
|
var barcode = r[2].substring(0, r[2].indexOf("\|")); |
||||
|
results.push(this.get_container_by_barcode(barcode)); |
||||
|
} else { |
||||
|
break; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
return results; |
||||
|
}, |
||||
|
|
||||
|
}); |
||||
|
|
||||
|
models.load_models({ |
||||
|
model: 'pos.container', |
||||
|
fields: ['name','barcode', 'weight'], |
||||
|
loaded: function(self, containers){ |
||||
|
self.db.add_containers(containers); |
||||
|
return self.load_placeholder_product(); |
||||
|
}, |
||||
|
}); |
||||
|
|
||||
|
}); |
@ -0,0 +1,244 @@ |
|||||
|
odoo.define('pos_container.tour.tare', function (require) { |
||||
|
"use strict"; |
||||
|
|
||||
|
var Tour = require('web_tour.tour'); |
||||
|
|
||||
|
function click_numpad(num) { |
||||
|
return { |
||||
|
content: "click on numpad button '" + num + "'", |
||||
|
trigger: ".input-button.number-char:contains('"+num+"')" |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
function scan(barcode) { |
||||
|
return { |
||||
|
content: "Scanning barcode " + barcode, |
||||
|
trigger: "input.ean", |
||||
|
run: "text " + barcode |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
function confirm_scan() { |
||||
|
return { |
||||
|
content: "Confirm barcode", |
||||
|
trigger: ".button.barcode", |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
function set_weight(weight) { |
||||
|
return { |
||||
|
content: "Setting weight " + weight, |
||||
|
trigger: "input.weight", |
||||
|
run: "text " + weight |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
function confirm_weight() { |
||||
|
return { |
||||
|
content: "Confirm weight", |
||||
|
trigger: ".button.set_weight", |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
function check_selected_orderline(message, check) { |
||||
|
return { |
||||
|
content: message, |
||||
|
trigger: ".orderline.selected " + check, |
||||
|
run: function () {}, // it's a check
|
||||
|
} |
||||
|
} |
||||
|
|
||||
|
|
||||
|
var steps = [{ |
||||
|
content: 'waiting for loading to finish', |
||||
|
trigger: '.o_main_content:has(.loader:hidden)', |
||||
|
run: function () {}, |
||||
|
}, |
||||
|
scan('0499999999998'), |
||||
|
confirm_scan(), |
||||
|
set_weight(0.1), |
||||
|
confirm_weight(), |
||||
|
{ |
||||
|
content: "Click on save", |
||||
|
trigger: ".add-container", |
||||
|
}, |
||||
|
// Test a second time with a custom name
|
||||
|
scan('0499999999981'), |
||||
|
confirm_scan(), |
||||
|
set_weight(0.2), |
||||
|
confirm_weight(), |
||||
|
{ |
||||
|
content: "Set a custom name", |
||||
|
trigger:"input.container-name", |
||||
|
run:"text TOTO", |
||||
|
}, { |
||||
|
content: "Click on save", |
||||
|
trigger: ".add-container", |
||||
|
}, |
||||
|
// Scan du premier contenant
|
||||
|
scan('0499999999998'), |
||||
|
confirm_scan(), |
||||
|
check_selected_orderline("Check: empty container in the orderline", ".product-name:contains('Container without product')"), |
||||
|
check_selected_orderline("Check: the name is 'Container'", ".info:contains('Container')"), |
||||
|
check_selected_orderline("Check: the quantity is 0", ".info em:contains('0.000')"), |
||||
|
{ |
||||
|
content: "select product", |
||||
|
trigger: ".product:contains('Whiteboard Pen')", //UoM = kg
|
||||
|
}, |
||||
|
set_weight(0.2), |
||||
|
confirm_weight(), |
||||
|
{ |
||||
|
content: "validate weight", |
||||
|
trigger: ".buy-product", |
||||
|
}, |
||||
|
check_selected_orderline("Check: the name is 'Container'", ".info:contains('Container')"), |
||||
|
check_selected_orderline("Check: orderline in AUTO tare mode", ".pos-right-align:contains('AUTO')"), |
||||
|
check_selected_orderline("Check: orderline's product is the Pen", ".product-name:contains('Whiteboard Pen')"), |
||||
|
check_selected_orderline("Check: the quantity is the tared weight", ".info:contains('0.200')"), |
||||
|
{ |
||||
|
content: "click container button", |
||||
|
trigger: ".control-button.o_container_button", |
||||
|
}, { |
||||
|
content: "Search Container TOTO", |
||||
|
trigger: ".searchbox input", |
||||
|
run: "text TOTO", |
||||
|
}, { |
||||
|
content: "Select container TOTO", |
||||
|
trigger: ".container-line:contains('TOTO')", |
||||
|
}, { |
||||
|
content: "Click delete", |
||||
|
trigger: ".button.delete-container", |
||||
|
}, { |
||||
|
content: "Click cancel", |
||||
|
trigger: ".button.cancel", |
||||
|
}, { |
||||
|
content: "Click delete", |
||||
|
trigger: ".button.delete-container", |
||||
|
}, { |
||||
|
content: "Click confirm", |
||||
|
trigger: ".button.confirm", |
||||
|
}, { |
||||
|
content: "Search by barcode", |
||||
|
trigger: ".searchbox input", |
||||
|
run: "text 0499999999998", |
||||
|
}, { |
||||
|
content: "select the searched container", |
||||
|
trigger: ".container-line:contains('Container')", |
||||
|
}, { |
||||
|
content: "confirm selection", |
||||
|
trigger: ".containerlist-screen .next", |
||||
|
}, { |
||||
|
content: "remove orderline quantity", |
||||
|
trigger: ".input-button.numpad-backspace", |
||||
|
}, { |
||||
|
content: "delete orderline", |
||||
|
trigger: ".input-button.numpad-backspace", |
||||
|
}, { |
||||
|
content: "select another product", |
||||
|
trigger: ".product:contains('Desk Organizer')", //UoM = kg
|
||||
|
}, |
||||
|
set_weight(0.5), |
||||
|
confirm_weight(), |
||||
|
{ |
||||
|
content: "confirm purchase", |
||||
|
trigger: ".buy-product", |
||||
|
}, { |
||||
|
content: "switch numpad to tare mode", |
||||
|
trigger: ".control-button.o_tare_button", |
||||
|
}, |
||||
|
click_numpad(0), |
||||
|
click_numpad('.'), |
||||
|
click_numpad(2), |
||||
|
check_selected_orderline("Check: orderline in MAN tare mode", ".pos-right-align:contains('MAN')"), |
||||
|
check_selected_orderline("Check: orderline's product is the Organizer", ".product-name:contains('Desk Organizer')"), |
||||
|
check_selected_orderline("Check: the quantity is the tared weight", ".info:contains('0.300')"), |
||||
|
{ |
||||
|
content: "click orderline auto", |
||||
|
trigger: ".orderline .pos-right-align:contains('AUTO')", |
||||
|
}, { |
||||
|
content: "switch numpad to tare mode", |
||||
|
trigger: ".control-button.o_tare_button", |
||||
|
}, |
||||
|
click_numpad(0), |
||||
|
click_numpad('.'), |
||||
|
click_numpad(2), |
||||
|
check_selected_orderline("Check: orderline in MAN tare mode", ".pos-right-align:contains('MAN')"), |
||||
|
check_selected_orderline("Check: orderline's product is the Pen", ".product-name:contains('Whiteboard Pen')"), |
||||
|
check_selected_orderline("Check: the quantity is the tared weight", ".info em:contains('0.100')"), |
||||
|
{ |
||||
|
content: "switch numpad to quantity mode", |
||||
|
trigger: ".mode-button[data-mode='quantity']", |
||||
|
}, |
||||
|
click_numpad(0), |
||||
|
click_numpad('.'), |
||||
|
click_numpad(6), |
||||
|
check_selected_orderline("Check: orderline in MAN tare mode", ".pos-right-align:contains('MAN')"), |
||||
|
check_selected_orderline("Check: orderline's product is the Pen", ".product-name:contains('Whiteboard Pen')"), |
||||
|
check_selected_orderline("Check: the quantity is 0.6", ".info em:contains('0.600')"), |
||||
|
check_selected_orderline("Check: the tare is unchanged", ".info:contains('0.2')"), |
||||
|
check_selected_orderline("Check: the gross weight is the tare + the quantity", ".info:contains('Gross : 0.8 kg')"), |
||||
|
{ |
||||
|
content: "Add a unit product", |
||||
|
trigger: ".product:contains('Large Cabinet')", |
||||
|
}, { |
||||
|
content: "click discount", |
||||
|
trigger: ".mode-button[data-mode='discount']", |
||||
|
}, |
||||
|
click_numpad(1), |
||||
|
click_numpad(0), |
||||
|
check_selected_orderline("Check: orderline in MAN tare mode", ".pos-right-align:contains('MAN')"), |
||||
|
check_selected_orderline("Check: the undiscounted price is still 320", ".info:contains('320.00')"), |
||||
|
{ |
||||
|
content: "Add a unit product", |
||||
|
trigger: ".product:contains('Large Cabinet')", |
||||
|
}, { |
||||
|
content: "click price change", |
||||
|
trigger: ".mode-button[data-mode='price']", |
||||
|
}, |
||||
|
click_numpad(2), |
||||
|
click_numpad(0), |
||||
|
click_numpad(0), |
||||
|
check_selected_orderline("Check: orderline in MAN tare mode", ".pos-right-align:contains('MAN')"), |
||||
|
// Ajouter une ligne en AUTO
|
||||
|
scan('0499999999998'), |
||||
|
confirm_scan(), |
||||
|
{ |
||||
|
content: "select product", |
||||
|
trigger: ".product:contains('Whiteboard Pen')", //UoM = kg
|
||||
|
}, |
||||
|
set_weight(0.3), |
||||
|
confirm_weight(), |
||||
|
{ |
||||
|
content: "validate weight", |
||||
|
trigger: ".buy-product", |
||||
|
}, |
||||
|
{ |
||||
|
content: "pay", |
||||
|
trigger: ".button.pay", |
||||
|
}, |
||||
|
click_numpad(2), |
||||
|
click_numpad(0), |
||||
|
click_numpad(0), |
||||
|
click_numpad(0), |
||||
|
{ |
||||
|
content: "validate", |
||||
|
trigger: ".button.next", |
||||
|
}]; |
||||
|
|
||||
|
|
||||
|
var autre = [{ |
||||
|
content: "relancer POS", |
||||
|
trigger: "", |
||||
|
}, { |
||||
|
content: "click commandes", |
||||
|
trigger: "", |
||||
|
}, { |
||||
|
content: "sélectionner dernière commande", |
||||
|
trigger: "", |
||||
|
}, { |
||||
|
content: "click reprint", |
||||
|
trigger: "", |
||||
|
}]; |
||||
|
|
||||
|
Tour.register('pos_container', { test: true, url: '/pos/web' }, steps); |
||||
|
}); |
@ -0,0 +1,442 @@ |
|||||
|
<?xml version="1.0" encoding="UTF-8"?> |
||||
|
<templates id="template" xml:space="preserve"> |
||||
|
|
||||
|
<t t-name="ContainerButton"> |
||||
|
<button class="control-button main o_container_button"> |
||||
|
<i class="fa fa-beer" role="img" aria-label="Container" title="Container"/> |
||||
|
Container |
||||
|
</button> |
||||
|
</t> |
||||
|
|
||||
|
<t t-name="TareButton"> |
||||
|
<button class="control-button second mode-button o_tare_button" data-mode="tare"> |
||||
|
Tare |
||||
|
</button> |
||||
|
</t> |
||||
|
|
||||
|
<t t-name="ContainerListScreenWidget"> |
||||
|
<div class="containerlist-screen screen"> |
||||
|
<div class="screen-content"> |
||||
|
<section class="top-content"> |
||||
|
<span class="button back"> |
||||
|
<i class="fa fa-angle-double-left"/> |
||||
|
Cancel |
||||
|
</span> |
||||
|
<span class="searchbox"> |
||||
|
<input placeholder="Search Containers"/> |
||||
|
<span class="search-clear"/> |
||||
|
</span> |
||||
|
<span class="searchbox"/> |
||||
|
<span class="button delete-container oe_hidden" role="img" aria-label="Delete container" title="Delete container"> |
||||
|
<i class="fa fa-beer"/> |
||||
|
<i class="fa fa-trash"/> |
||||
|
</span> |
||||
|
<span class="button next oe_hidden highlight"> |
||||
|
Select a container |
||||
|
<i class="fa fa-angle-double-right"/> |
||||
|
</span> |
||||
|
</section> |
||||
|
<section class="full-content"> |
||||
|
<div class="window"> |
||||
|
<section class="subwindow"> |
||||
|
<div class="subwindow-container"> |
||||
|
<div class="subwindow-container-fix touch-scrollable scrollable-y"> |
||||
|
<table class="container-list"> |
||||
|
<thead> |
||||
|
<tr> |
||||
|
<th>Name</th> |
||||
|
<th>Barcode</th> |
||||
|
<th>Weight</th> |
||||
|
</tr> |
||||
|
</thead> |
||||
|
<tbody class="container-list-contents"> |
||||
|
</tbody> |
||||
|
</table> |
||||
|
</div> |
||||
|
</div> |
||||
|
</section> |
||||
|
</div> |
||||
|
</section> |
||||
|
</div> |
||||
|
</div> |
||||
|
</t> |
||||
|
|
||||
|
<t t-name="ContainerLine"> |
||||
|
<tr class="container-line" t-att-data-id="container.barcode"> |
||||
|
<td> |
||||
|
<t t-esc="container.name"/> |
||||
|
</td> |
||||
|
<td> |
||||
|
<t t-esc="container.barcode"/> |
||||
|
</td> |
||||
|
<td> |
||||
|
<t t-esc="container.weight"/> |
||||
|
</td> |
||||
|
</tr> |
||||
|
</t> |
||||
|
|
||||
|
<t t-extend='Orderline'> |
||||
|
<t t-jquery='.info-list:last-child' t-operation='prepend'> |
||||
|
<t t-if="line.get_container()"> |
||||
|
<ul class="info-list"> |
||||
|
<ul class="info-list"> |
||||
|
<i><t t-if="line.get_gross_weight()"> |
||||
|
<li class="info"> |
||||
|
Gross : <t t-esc="line.get_gross_weight()"/> kg |
||||
|
</li> |
||||
|
</t> |
||||
|
<li class="info"> |
||||
|
<i class='fa fa-beer'/> : |
||||
|
<t t-esc="line.get_container().weight"/> kg |
||||
|
- |
||||
|
<t t-esc="line.get_container().name"/> |
||||
|
</li></i> |
||||
|
</ul> |
||||
|
</ul> |
||||
|
</t> |
||||
|
<t t-if="line.get_tare()"> |
||||
|
<ul class="info-list"> |
||||
|
<ul class="info-list"> |
||||
|
<i><t t-if="line.get_gross_weight()"> |
||||
|
<li class="info"> |
||||
|
Gross : <t t-esc="line.get_gross_weight()"/> kg |
||||
|
</li> |
||||
|
</t> |
||||
|
<li class="info"> |
||||
|
<i class='fa fa-beer'/> : |
||||
|
<t t-esc="line.get_tare()"/> kg |
||||
|
- Manual tare |
||||
|
</li></i> |
||||
|
</ul> |
||||
|
</ul> |
||||
|
</t> |
||||
|
<div class="pos-right-align"> |
||||
|
<t t-esc="line.get_tare_mode()"/> |
||||
|
</div> |
||||
|
</t> |
||||
|
</t> |
||||
|
|
||||
|
<t t-name="ContainerScaleScreenWidget"> |
||||
|
<div class="scale-screen screen"> |
||||
|
<div class="screen-content"> |
||||
|
<div class="top-content"> |
||||
|
<span class='button back'> |
||||
|
<i class='fa fa-angle-double-left'></i> |
||||
|
Back |
||||
|
</span> |
||||
|
<h1 class='product-name'>Add a container</h1> |
||||
|
</div> |
||||
|
<div class="centered-content"> |
||||
|
<div class='weight js-weight'> |
||||
|
<t t-esc="widget.get_product_weight_string()" /> |
||||
|
</div> |
||||
|
<div class='container-name'> |
||||
|
<span class='label'>Container name: </span><br/> |
||||
|
<input class='detail container-name' name='container_name' placeholder="Container"></input> |
||||
|
</div> |
||||
|
<div class='add-container'> |
||||
|
Save |
||||
|
<i class='fa fa-angle-double-right'></i> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
</t> |
||||
|
|
||||
|
<t t-extend="PosTicket"> |
||||
|
<t t-jquery='.receipt-orderlines' t-operation='inner'> |
||||
|
<table> |
||||
|
<colgroup> |
||||
|
<col width='50%' /> |
||||
|
<col width='25%' /> |
||||
|
<col width='25%' /> |
||||
|
</colgroup> |
||||
|
<tr t-foreach="orderlines" t-as="orderline"> |
||||
|
<t t-if="orderline.get_tare_mode() == undefined |
||||
|
and orderline.product.barcode != 'CONTAINER'"> |
||||
|
<td> |
||||
|
<t t-esc="orderline.get_product().display_name"/> |
||||
|
<t t-if="orderline.get_discount() > 0"> |
||||
|
<div class="pos-disc-font"> |
||||
|
With a <t t-esc="orderline.get_discount()"/>% discount |
||||
|
</div> |
||||
|
</t> |
||||
|
</td> |
||||
|
<td class="pos-right-align"> |
||||
|
<t t-esc="orderline.get_quantity_str_with_unit()"/> |
||||
|
</td> |
||||
|
<td class="pos-right-align"> |
||||
|
<t t-esc="widget.format_currency(orderline.get_display_price())"/> |
||||
|
</td> |
||||
|
</t> |
||||
|
</tr> |
||||
|
</table> |
||||
|
<t t-if="order.has_tare_line('AUTO')"> |
||||
|
<table> |
||||
|
<colgroup> |
||||
|
<col width='20%' /> |
||||
|
<col width='60%' /> |
||||
|
<col width='20%' /> |
||||
|
</colgroup> |
||||
|
<td></td> |
||||
|
<td> |
||||
|
<center>------------------------</center> |
||||
|
<center>Automatic Weighing</center> |
||||
|
<center>------------------------</center> |
||||
|
</td> |
||||
|
</table> |
||||
|
</t> |
||||
|
<table> |
||||
|
<colgroup> |
||||
|
<col width='50%' /> |
||||
|
<col width='25%' /> |
||||
|
<col width='25%' /> |
||||
|
</colgroup> |
||||
|
<tr t-foreach="orderlines" t-as="orderline"> |
||||
|
<t t-if="orderline.get_tare_mode() == 'AUTO'"> |
||||
|
<tr> |
||||
|
<td> |
||||
|
<t t-esc="orderline.get_product().display_name"/> |
||||
|
<t t-if="orderline.get_discount() > 0"> |
||||
|
<div class="pos-disc-font"> |
||||
|
With a <t t-esc="orderline.get_discount()"/>% discount |
||||
|
</div> |
||||
|
</t> |
||||
|
</td> |
||||
|
<td/> |
||||
|
<td class="pos-right-align"> |
||||
|
<t t-esc="widget.format_currency(orderline.get_display_price())"/> |
||||
|
</td> |
||||
|
</tr> |
||||
|
<tr> |
||||
|
<td> |
||||
|
<div style="margin-left:5%"> |
||||
|
<t t-esc="orderline.get_quantity_str_with_unit()"/> |
||||
|
x |
||||
|
<t t-esc="widget.format_currency(orderline.get_unit_display_price())"/>/<t t-esc="orderline.get_unit().name"/> |
||||
|
</div> |
||||
|
</td> |
||||
|
</tr> |
||||
|
<t t-if="orderline.get_container()"> |
||||
|
<tr> |
||||
|
<td> |
||||
|
<div style="margin-left:5%"> |
||||
|
Tare : <t t-esc="orderline.get_container().weight"/> |
||||
|
<t t-esc="orderline.get_unit().name"/> |
||||
|
</div> |
||||
|
</td> |
||||
|
</tr> |
||||
|
</t> |
||||
|
<t t-if="orderline.get_tare()"> |
||||
|
<tr> |
||||
|
<td> |
||||
|
<div style="margin-left:5%"> |
||||
|
Tare : <t t-esc="orderline.get_tare()"/> |
||||
|
<t t-esc="orderline.get_unit().name"/> |
||||
|
</div> |
||||
|
</td> |
||||
|
</tr> |
||||
|
</t> |
||||
|
</t> |
||||
|
</tr> |
||||
|
</table> |
||||
|
<t t-if="order.has_tare_line('MAN')"> |
||||
|
<table> |
||||
|
<colgroup> |
||||
|
<col width='20%' /> |
||||
|
<col width='60%' /> |
||||
|
<col width='20%' /> |
||||
|
</colgroup> |
||||
|
<td></td> |
||||
|
<td> |
||||
|
<center>------------------------</center> |
||||
|
<center>Manual Input</center> |
||||
|
<center>------------------------</center> |
||||
|
</td> |
||||
|
</table> |
||||
|
</t> |
||||
|
<table> |
||||
|
<colgroup> |
||||
|
<col width='50%' /> |
||||
|
<col width='25%' /> |
||||
|
<col width='25%' /> |
||||
|
</colgroup> |
||||
|
<tr t-foreach="orderlines" t-as="orderline"> |
||||
|
<t t-if="orderline.get_tare_mode() == 'MAN'"> |
||||
|
<tr> |
||||
|
<td> |
||||
|
<t t-esc="orderline.get_product().display_name"/> |
||||
|
<t t-if="orderline.get_discount() > 0"> |
||||
|
<div class="pos-disc-font"> |
||||
|
With a <t t-esc="orderline.get_discount()"/>% discount |
||||
|
</div> |
||||
|
</t> |
||||
|
</td> |
||||
|
<td class="pos-right-align"> |
||||
|
<t t-esc="orderline.get_quantity_str_with_unit()"/> |
||||
|
</td> |
||||
|
<td class="pos-right-align"> |
||||
|
<t t-esc="widget.format_currency(orderline.get_display_price())"/> |
||||
|
</td> |
||||
|
</tr> |
||||
|
<t t-if="orderline.get_tare()"> |
||||
|
<tr> |
||||
|
<td> |
||||
|
<div style="margin-left:5%"> |
||||
|
Tare : <t t-esc="orderline.tare"/> |
||||
|
<t t-esc="orderline.get_unit().name"/> |
||||
|
</div> |
||||
|
</td> |
||||
|
</tr> |
||||
|
</t> |
||||
|
</t> |
||||
|
</tr> |
||||
|
</table> |
||||
|
</t> |
||||
|
</t> |
||||
|
|
||||
|
<t t-extend="XmlReceipt"> |
||||
|
<t t-jquery='.orderlines' t-operation='inner'> |
||||
|
<t t-foreach='receipt.orderlines' t-as='line'> |
||||
|
<t t-if="line.tare_mode == undefined and line.product_barcode != 'CONTAINER'"> |
||||
|
<t t-set='simple' t-value='line.discount === 0 and line.unit_name === "Unit(s)" and line.quantity === 1' /> |
||||
|
<t t-if='simple'> |
||||
|
<line> |
||||
|
<left><t t-esc='line.product_name_wrapped[0]' /></left> |
||||
|
<right><value t-att-value-decimals='pos.currency.decimals'><t t-esc='line.price_display' /></value></right> |
||||
|
</line> |
||||
|
<t t-call="XmlReceiptWrappedProductNameLines"/> |
||||
|
</t> |
||||
|
<t t-if='!simple'> |
||||
|
<line><left><t t-esc='line.product_name_wrapped[0]' /></left></line> |
||||
|
<t t-call="XmlReceiptWrappedProductNameLines"/> |
||||
|
<t t-if='line.discount !== 0'> |
||||
|
<line indent='1'><left>Discount: <t t-esc='line.discount' />%</left></line> |
||||
|
</t> |
||||
|
<line indent='1'> |
||||
|
<left> |
||||
|
<value t-att-value-decimals='pos.dp["Product Unit of Measure"]' value-autoint='on'> |
||||
|
<t t-esc='line.quantity' /> |
||||
|
</value> |
||||
|
<t t-if='line.unit_name !== "Unit(s)"'> |
||||
|
<t t-esc='line.unit_name' /> |
||||
|
</t> |
||||
|
x |
||||
|
<value t-att-value-decimals='pos.dp["Product Price"]'> |
||||
|
<t t-esc='line.price' /> |
||||
|
</value> |
||||
|
</left> |
||||
|
<right> |
||||
|
<value t-att-value-decimals='pos.currency.decimals'><t t-esc='line.price_display' /></value> |
||||
|
</right> |
||||
|
</line> |
||||
|
</t> |
||||
|
</t> |
||||
|
</t> |
||||
|
<div>------------------</div> |
||||
|
<t t-if="receipt.has_tare_mode.auto"> |
||||
|
Automatic Weighing |
||||
|
<div>------------------</div> |
||||
|
<t t-foreach='receipt.orderlines' t-as='line'> |
||||
|
<t t-if="line.tare_mode == 'AUTO'"> |
||||
|
<t t-set='simple' t-value='line.discount === 0 and line.unit_name === "Unit(s)" and line.quantity === 1' /> |
||||
|
<t t-if='simple'> |
||||
|
<line> |
||||
|
<left><t t-esc='line.product_name_wrapped[0]' /></left> |
||||
|
<right><value t-att-value-decimals='pos.currency.decimals'><t t-esc='line.price_display' /></value></right> |
||||
|
</line> |
||||
|
<t t-call="XmlReceiptWrappedProductNameLines"/> |
||||
|
</t> |
||||
|
<t t-if='!simple'> |
||||
|
<line><left><t t-esc='line.product_name_wrapped[0]' /></left></line> |
||||
|
<t t-call="XmlReceiptWrappedProductNameLines"/> |
||||
|
<t t-if='line.discount !== 0'> |
||||
|
<line indent='1'><left>Discount: <t t-esc='line.discount' />%</left></line> |
||||
|
</t> |
||||
|
<line indent='1'> |
||||
|
<left> |
||||
|
<value t-att-value-decimals='pos.dp["Product Unit of Measure"]' value-autoint='on'> |
||||
|
<t t-esc='line.quantity' /> |
||||
|
</value> |
||||
|
<t t-if='line.unit_name !== "Unit(s)"'> |
||||
|
<t t-esc='line.unit_name' /> |
||||
|
</t> |
||||
|
x |
||||
|
<value t-att-value-decimals='pos.dp["Product Price"]'> |
||||
|
<t t-esc='line.price' /> |
||||
|
</value> |
||||
|
</left> |
||||
|
<right> |
||||
|
<value t-att-value-decimals='pos.currency.decimals'><t t-esc='line.price_display' /></value> |
||||
|
</right> |
||||
|
</line> |
||||
|
<t t-if='line.container'> |
||||
|
<line indent='1'> |
||||
|
<left> |
||||
|
Tare : <t t-esc='line.container.weight' /><t t-esc='line.unit_name' /> |
||||
|
</left> |
||||
|
</line> |
||||
|
</t> |
||||
|
<t t-if='line.tare'> |
||||
|
<line indent='1'> |
||||
|
<left> |
||||
|
Tare : <t t-esc='line.tare' /><t t-esc='line.unit_name' /> |
||||
|
</left> |
||||
|
</line> |
||||
|
</t> |
||||
|
</t> |
||||
|
</t> |
||||
|
</t> |
||||
|
<div>------------------</div> |
||||
|
</t> |
||||
|
<t t-if="receipt.has_tare_mode.manual"> |
||||
|
Manual Input |
||||
|
<div>------------------</div> |
||||
|
<t t-foreach='receipt.orderlines' t-as='line'> |
||||
|
<t t-if="line.tare_mode == 'MAN'"> |
||||
|
<t t-set='simple' t-value='line.discount === 0 and line.unit_name === "Unit(s)" and line.quantity === 1' /> |
||||
|
<t t-if='simple'> |
||||
|
<line> |
||||
|
<left><t t-esc='line.product_name_wrapped[0]' /></left> |
||||
|
<right><value t-att-value-decimals='pos.currency.decimals'><t t-esc='line.price_display' /></value></right> |
||||
|
</line> |
||||
|
<t t-call="XmlReceiptWrappedProductNameLines"/> |
||||
|
</t> |
||||
|
<t t-if='!simple'> |
||||
|
<line><left><t t-esc='line.product_name_wrapped[0]' /></left></line> |
||||
|
<t t-call="XmlReceiptWrappedProductNameLines"/> |
||||
|
<t t-if='line.discount !== 0'> |
||||
|
<line indent='1'><left>Discount: <t t-esc='line.discount' />%</left></line> |
||||
|
</t> |
||||
|
<line indent='1'> |
||||
|
<left> |
||||
|
<value t-att-value-decimals='pos.dp["Product Unit of Measure"]' value-autoint='on'> |
||||
|
<t t-esc='line.quantity' /> |
||||
|
</value> |
||||
|
<t t-if='line.unit_name !== "Unit(s)"'> |
||||
|
<t t-esc='line.unit_name' /> |
||||
|
</t> |
||||
|
x |
||||
|
<value t-att-value-decimals='pos.dp["Product Price"]'> |
||||
|
<t t-esc='line.price' /> |
||||
|
</value> |
||||
|
</left> |
||||
|
<right> |
||||
|
<value t-att-value-decimals='pos.currency.decimals'><t t-esc='line.price_display' /></value> |
||||
|
</right> |
||||
|
</line> |
||||
|
<t t-if='line.tare'> |
||||
|
<line indent='1'> |
||||
|
<left> |
||||
|
Tare : <t t-esc='line.tare' /><t t-esc='line.unit_name' /> |
||||
|
</left> |
||||
|
</line> |
||||
|
</t> |
||||
|
</t> |
||||
|
</t> |
||||
|
</t> |
||||
|
</t> |
||||
|
</t> |
||||
|
</t> |
||||
|
|
||||
|
</templates> |
@ -0,0 +1,17 @@ |
|||||
|
<?xml version="1.0" encoding="utf-8"?> |
||||
|
<!-- |
||||
|
Copyright 2019 Coop IT Easy SCRLfs |
||||
|
Robin Keunen <robin@coopiteasy.be> |
||||
|
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). |
||||
|
--> |
||||
|
|
||||
|
<odoo> |
||||
|
<template id="assets_frontend" inherit_id="point_of_sale.assets"> |
||||
|
<xpath expr="." position="inside"> |
||||
|
<link href="/pos_container/static/src/css/container.css" rel="stylesheet"/> |
||||
|
<script type="text/javascript" src="/pos_container/static/src/js/models_and_db.js"/> |
||||
|
<script type="text/javascript" src="/pos_container/static/src/js/container.js"/> |
||||
|
<script type="text/javascript" src="/pos_container/static/src/js/tests.js"/> |
||||
|
</xpath> |
||||
|
</template> |
||||
|
</odoo> |
@ -0,0 +1 @@ |
|||||
|
from . import test_pos_container |
@ -0,0 +1,14 @@ |
|||||
|
import odoo.tests |
||||
|
|
||||
|
|
||||
|
@odoo.tests.tagged('pos_install', '-at-install') |
||||
|
class TestUi(odoo.tests.HttpCase): |
||||
|
|
||||
|
def test_01_pos_container_tour(self): |
||||
|
self.phantom_js( |
||||
|
"/web", |
||||
|
"odoo.__DEBUG__.services['web_tour.tour']" + |
||||
|
".run('pos_container_tour')", |
||||
|
"odoo.__DEBUG__.services['web_tour.tour']" + |
||||
|
".tours.pos_container_tour.ready", |
||||
|
login="admin") |
@ -0,0 +1,43 @@ |
|||||
|
<odoo> |
||||
|
<record id="pos_container_tree_view" model="ir.ui.view"> |
||||
|
<field name="name">pos.container.tree</field> |
||||
|
<field name="model">pos.container</field> |
||||
|
<field name="arch" type="xml"> |
||||
|
<tree> |
||||
|
<field name="name"/> |
||||
|
<field name="barcode"/> |
||||
|
<field name="weight"/> |
||||
|
</tree> |
||||
|
</field> |
||||
|
</record> |
||||
|
|
||||
|
<record id="pos_container_form_view" model="ir.ui.view"> |
||||
|
<field name="name">pos.container.form</field> |
||||
|
<field name="model">pos.container</field> |
||||
|
<field name="arch" type="xml"> |
||||
|
<form> |
||||
|
<sheet> |
||||
|
<group> |
||||
|
<field name="name"/> |
||||
|
<field name="barcode"/> |
||||
|
<field name="weight"/> |
||||
|
</group> |
||||
|
</sheet> |
||||
|
</form> |
||||
|
</field> |
||||
|
</record> |
||||
|
|
||||
|
<record id="pos_container_action_window" model="ir.actions.act_window" > |
||||
|
<field name="name">Containers</field> |
||||
|
<field name="res_model">pos.container</field> |
||||
|
<field name="view_mode">tree,form</field> |
||||
|
</record> |
||||
|
|
||||
|
<menuitem id="pos_container_menu" |
||||
|
name="Containers" |
||||
|
parent="point_of_sale.pos_config_menu_catalog" |
||||
|
sequence="13" |
||||
|
action="pos_container_action_window" |
||||
|
groups="point_of_sale.group_pos_manager,point_of_sale.group_pos_user" |
||||
|
/> |
||||
|
</odoo> |
@ -0,0 +1,3 @@ |
|||||
|
# -*- coding: utf-8 -*- |
||||
|
|
||||
|
from . import models |
@ -0,0 +1,33 @@ |
|||||
|
# -*- coding: utf-8 -*- |
||||
|
# Copyright 2019 Coop IT Easy SCRLfs |
||||
|
# Vincent Van Rossem <vvrossem@gmail.com> |
||||
|
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). |
||||
|
|
||||
|
{ |
||||
|
'name': 'Currency Management Extension to POS Customer Display', |
||||
|
|
||||
|
'version': '12.0.1.0.0', |
||||
|
|
||||
|
'category': 'Point Of Sale', |
||||
|
|
||||
|
'summary': """ |
||||
|
Add Currency Management to POS Customer Display device""", |
||||
|
|
||||
|
"author": "Coop IT Easy SCRLfs, " |
||||
|
"Odoo Community Association (OCA)", |
||||
|
|
||||
|
'license': 'AGPL-3', |
||||
|
|
||||
|
'depends': [ |
||||
|
'pos_customer_display' |
||||
|
], |
||||
|
|
||||
|
'data': [ |
||||
|
'templates/templates.xml', |
||||
|
'views/pos_config_view.xml', |
||||
|
], |
||||
|
|
||||
|
'demo': [], |
||||
|
|
||||
|
'installable': True, |
||||
|
} |
@ -0,0 +1,3 @@ |
|||||
|
# -*- coding: utf-8 -*- |
||||
|
|
||||
|
from . import pos_customer_display_currency |
@ -0,0 +1,30 @@ |
|||||
|
# -*- coding: utf-8 -*- |
||||
|
# Copyright 2019 Coop IT Easy SCRLfs |
||||
|
# Vincent Van Rossem <vvrossem@gmail.com> |
||||
|
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). |
||||
|
|
||||
|
from odoo import models, fields, api, _ |
||||
|
from odoo.exceptions import ValidationError |
||||
|
|
||||
|
|
||||
|
class PosConfig(models.Model): |
||||
|
_inherit = 'pos.config' |
||||
|
|
||||
|
# TODO(Vincent) add field customer_display_currency_code or use/fetch Odoo's default currency |
||||
|
customer_display_currency_char = fields.Char( |
||||
|
size=1, |
||||
|
required=True, |
||||
|
string="User-defined Currency Character", default="$", |
||||
|
help="The ASCII character to use for drawing the default currency symbol on the device.") |
||||
|
|
||||
|
@api.constrains('customer_display_currency_char') |
||||
|
def _check_currency_char(self): |
||||
|
""" |
||||
|
char_code can only be defined between character hex codes \x20 and \xFF |
||||
|
(or decimal codes 32 and 255) |
||||
|
|
||||
|
""" |
||||
|
self.ensure_one() |
||||
|
if not 32 <= ord(self.customer_display_currency_char) <= 255: |
||||
|
raise ValidationError("User-defined Currency Character must be defined between " |
||||
|
"character codes 20h (32) and FFh (255)") |
@ -0,0 +1,310 @@ |
|||||
|
/* |
||||
|
Copyright 2019 Coop IT Easy SCRLfs |
||||
|
Vincent Van Rossem <vvrossem@gmail.com> |
||||
|
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
|
||||
|
*/ |
||||
|
|
||||
|
odoo.define('pos_customer_display_currency.pos_customer_display_currency', function (require) { |
||||
|
"use strict"; |
||||
|
var chrome = require('point_of_sale.chrome'); |
||||
|
var core = require('web.core'); |
||||
|
var utils = require('web.utils') |
||||
|
var devices = require('point_of_sale.devices'); |
||||
|
var gui = require('point_of_sale.gui'); |
||||
|
var models = require('point_of_sale.models'); |
||||
|
var screens = require('point_of_sale.screens'); |
||||
|
var _t = core._t; |
||||
|
|
||||
|
var timerID_total; |
||||
|
var timerID_updated; |
||||
|
|
||||
|
var round_pr = utils.round_precision; |
||||
|
|
||||
|
models.PosModel = models.PosModel.extend({ |
||||
|
/** |
||||
|
* Prepare and send the currency data to the customer display device |
||||
|
*/ |
||||
|
prepare_currency_data_customer_display: function () { |
||||
|
var currency_data = { |
||||
|
'currency_code': this.currency.name || this.company_currency.name, |
||||
|
'currency_char': this.config.customer_display_currency_char |
||||
|
}; |
||||
|
this.proxy.send_currency_data_customer_display(currency_data); |
||||
|
}, |
||||
|
|
||||
|
/** |
||||
|
* Prepare and send a text to the customer display device according to param type |
||||
|
* @override prepare_text_customer_display from customer_display.js (module pos_customer_display) |
||||
|
* @param {string} type |
||||
|
* @param data |
||||
|
*/ |
||||
|
prepare_text_customer_display: function (type, data) { |
||||
|
if (!this.config.iface_customer_display) |
||||
|
return; |
||||
|
var line_length = this.config.customer_display_line_length || 20; |
||||
|
var currency_rounding = this.currency.decimals; |
||||
|
var currency_char = this.config.customer_display_currency_char; |
||||
|
var previous_lines_to_send, updated_lines_to_send, lines_to_send, total_lines = []; |
||||
|
var line, product, container = {}; |
||||
|
var l21 = ""; |
||||
|
var l22 = ""; |
||||
|
var total = ""; |
||||
|
var mode = $('.selected-mode').attr('data-mode'); // numpad selected mode
|
||||
|
|
||||
|
if (timerID_updated){ |
||||
|
clearTimeout(timerID_updated); |
||||
|
} |
||||
|
if (timerID_total){ |
||||
|
clearTimeout(timerID_total); |
||||
|
} |
||||
|
|
||||
|
switch(type) { |
||||
|
case 'add_update_line': |
||||
|
line = data['line']; |
||||
|
if ((line.qty_manually_set && mode === 'quantity') || mode === 'tare' || mode === 'price') { |
||||
|
// first display "Manual Entry"
|
||||
|
l21 = line.get_quantity_str_with_uom() |
||||
|
+ 'x' |
||||
|
+ line.get_unit_price_with_uom_currency(currency_char, currency_rounding); |
||||
|
previous_lines_to_send = [ |
||||
|
this.proxy.align_left(_t('Manual Entry'), line_length), |
||||
|
this.proxy.align_right(l21, line_length) |
||||
|
]; |
||||
|
this.proxy.send_text_customer_display(previous_lines_to_send, line_length); |
||||
|
|
||||
|
// then display updated product after 3s
|
||||
|
l22 = ' ' + line.get_display_price().toFixed(currency_rounding) + currency_char; |
||||
|
updated_lines_to_send = [ |
||||
|
this.proxy.align_left(line.get_product().display_name, line_length - l22.length) + l22, |
||||
|
this.proxy.align_left(l21, line_length) |
||||
|
]; |
||||
|
timerID_updated = setTimeout(function () { |
||||
|
this.proxy.send_text_customer_display(updated_lines_to_send, line_length); |
||||
|
}.bind(this),3000); |
||||
|
|
||||
|
} else if (!line.qty_manually_set && mode === 'quantity') { |
||||
|
// first display added product
|
||||
|
l21 = line.get_quantity_str_with_uom() |
||||
|
+ 'x' |
||||
|
+ line.get_unit_price_with_uom_currency(currency_char, currency_rounding); |
||||
|
l22 = ' ' + line.get_display_price().toFixed(currency_rounding) + currency_char; |
||||
|
previous_lines_to_send = [ |
||||
|
this.proxy.align_left(line.get_product().display_name, line_length - l22.length) + l22, |
||||
|
this.proxy.align_left(l21, line_length) |
||||
|
]; |
||||
|
this.proxy.send_text_customer_display(previous_lines_to_send, line_length); |
||||
|
|
||||
|
} else if (mode === 'discount') { |
||||
|
// first display discount information
|
||||
|
var discount = line.get_discount(); |
||||
|
l22 = ' ' + line.get_base_price().toFixed(currency_rounding) + currency_char; |
||||
|
previous_lines_to_send = [ |
||||
|
this.proxy.align_left(line.get_product().display_name, line_length - l22.length) + l22, |
||||
|
this.proxy.align_left(_t("Discount:") + discount + '%', line_length) |
||||
|
]; |
||||
|
this.proxy.send_text_customer_display(previous_lines_to_send, line_length); |
||||
|
|
||||
|
// then display updated product after 3s
|
||||
|
l21 = line.get_quantity_str_with_uom() |
||||
|
+ 'x' |
||||
|
+ line.get_base_price().toFixed(currency_rounding) + currency_char; |
||||
|
updated_lines_to_send = [ |
||||
|
this.proxy.align_left(line.get_product().display_name, line_length - l22.length) + l22, |
||||
|
this.proxy.align_left(l21, line_length) |
||||
|
]; |
||||
|
timerID_updated = setTimeout(function () { |
||||
|
this.proxy.send_text_customer_display(updated_lines_to_send, line_length); |
||||
|
}.bind(this),3000); |
||||
|
} |
||||
|
break; |
||||
|
|
||||
|
case 'add_container': |
||||
|
line = data['line']; |
||||
|
container = line.get_container(); |
||||
|
previous_lines_to_send = [ |
||||
|
this.proxy.align_left(container.name, line_length), |
||||
|
this.proxy.align_right(container.weight.toString() + ' kg', line_length) |
||||
|
]; |
||||
|
this.proxy.send_text_customer_display(previous_lines_to_send, line_length); |
||||
|
break; |
||||
|
|
||||
|
case 'remove_orderline': |
||||
|
// first click on the backspace button set the amount to 0
|
||||
|
// => we can't precise the deleted quantity and price
|
||||
|
line = data['line']; |
||||
|
product = line.get_product(); |
||||
|
if (line.container) { |
||||
|
lines_to_send = [ |
||||
|
this.proxy.align_left(_t("Delete Container"), line_length), |
||||
|
this.proxy.align_right(line.container.name, line_length) |
||||
|
]; |
||||
|
|
||||
|
} else if (product) { |
||||
|
lines_to_send = [ |
||||
|
this.proxy.align_left(_t("Delete Item"), line_length), |
||||
|
this.proxy.align_right(product.display_name, line_length) |
||||
|
]; |
||||
|
} |
||||
|
this.proxy.send_text_customer_display(lines_to_send, line_length); |
||||
|
break; |
||||
|
|
||||
|
case 'add_paymentline': |
||||
|
total = this.get('selectedOrder').get_total_with_tax().toFixed(currency_rounding) + currency_char; |
||||
|
lines_to_send = [ |
||||
|
this.proxy.align_left(_t("TOTAL:"), line_length), |
||||
|
this.proxy.align_right(total, line_length) |
||||
|
]; |
||||
|
this.proxy.send_text_customer_display(lines_to_send, line_length); |
||||
|
break; |
||||
|
|
||||
|
case 'remove_paymentline': |
||||
|
line = data['line']; |
||||
|
var amount = line.get_amount().toFixed(currency_rounding) + currency_char; |
||||
|
lines_to_send = [ |
||||
|
this.proxy.align_left(_t("Cancel Payment"), line_length), |
||||
|
this.proxy.align_right(line.cashregister.journal_id[1], line_length - 1 - amount.length) + ' ' + amount |
||||
|
]; |
||||
|
this.proxy.send_text_customer_display(lines_to_send, line_length); |
||||
|
break; |
||||
|
|
||||
|
case 'update_payment': |
||||
|
var change = data['change'] + currency_char; |
||||
|
lines_to_send = [ |
||||
|
this.proxy.align_left(_t("Your Change:"), line_length), |
||||
|
this.proxy.align_right(change, line_length) |
||||
|
]; |
||||
|
this.proxy.send_text_customer_display(lines_to_send, line_length); |
||||
|
break; |
||||
|
|
||||
|
// same display for both types
|
||||
|
case 'push_order': |
||||
|
case 'openPOS': |
||||
|
lines_to_send = [ |
||||
|
this.proxy.align_center(this.config.customer_display_msg_next_l1, line_length), |
||||
|
this.proxy.align_center(this.config.customer_display_msg_next_l2, line_length) |
||||
|
]; |
||||
|
this.proxy.send_text_customer_display(lines_to_send, line_length); |
||||
|
break; |
||||
|
|
||||
|
case 'closePOS': |
||||
|
lines_to_send = [ |
||||
|
this.proxy.align_center(this.config.customer_display_msg_closed_l1, line_length), |
||||
|
this.proxy.align_center(this.config.customer_display_msg_closed_l2, line_length) |
||||
|
]; |
||||
|
this.proxy.send_text_customer_display(lines_to_send, line_length); |
||||
|
break; |
||||
|
|
||||
|
default: |
||||
|
console.warn('Unknown message type'); |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
if ((type === 'add_update_line' && mode === 'quantity' && !line.qty_manually_set) |
||||
|
|| type === 'add_container' || type === 'remove_orderline') { |
||||
|
// display total after 3s
|
||||
|
var order = this.get('selectedOrder'); |
||||
|
if (order){ |
||||
|
total = order.get_total_with_tax().toFixed(currency_rounding) + currency_char; |
||||
|
total_lines = [ |
||||
|
this.proxy.align_left(_t("TOTAL:"), line_length), |
||||
|
this.proxy.align_right(total, line_length) |
||||
|
]; |
||||
|
timerID_total = setTimeout(function() {this.proxy.send_text_customer_display(total_lines, line_length); }.bind(this), 3000); |
||||
|
} |
||||
|
} else if ((type === 'add_update_line' && mode === 'quantity' && line.qty_manually_set) |
||||
|
|| mode === 'price' || mode === 'discount' || mode === 'tare') { |
||||
|
// then display total after 6s
|
||||
|
total = this.get('selectedOrder').get_total_with_tax().toFixed(currency_rounding) + currency_char; |
||||
|
total_lines = [ |
||||
|
this.proxy.align_left(_t("TOTAL:"), line_length), |
||||
|
this.proxy.align_right(total, line_length) |
||||
|
]; |
||||
|
timerID_total = setTimeout(function() {this.proxy.send_text_customer_display(total_lines, line_length); }.bind(this), 6000); |
||||
|
} |
||||
|
}, |
||||
|
}); |
||||
|
|
||||
|
devices.ProxyDevice = devices.ProxyDevice.extend({ |
||||
|
/** |
||||
|
* Send currency data to the customer display device |
||||
|
* @param currency_data |
||||
|
* @returns {*} |
||||
|
*/ |
||||
|
send_currency_data_customer_display: function (currency_data) { |
||||
|
return this.message('send_currency_data_customer_display', |
||||
|
{ |
||||
|
'currency_data': JSON.stringify(currency_data) |
||||
|
}); |
||||
|
}, |
||||
|
}); |
||||
|
|
||||
|
models.Orderline = models.Orderline.extend({ |
||||
|
/** |
||||
|
* This function is for the Bixolon only |
||||
|
* Returns quantityStr with or without the name of the unit of measure (uom) |
||||
|
*/ |
||||
|
get_quantity_str_with_uom: function(){ |
||||
|
var unit = this.get_unit(); |
||||
|
if(unit && !unit.is_pos_groupable){ |
||||
|
return this.quantityStr + '' + unit.name; |
||||
|
}else{ |
||||
|
return round_pr(this.quantity, 0.1); |
||||
|
} |
||||
|
}, |
||||
|
|
||||
|
/** |
||||
|
* This function is for the Bixolon display device only. |
||||
|
* Returns the unit price with the user-defined currency symbol (default: '$') |
||||
|
*/ |
||||
|
get_unit_price_with_uom_currency: function(currency_char, currency_rounding){ |
||||
|
var unit = this.get_unit(); |
||||
|
if(unit && !unit.is_pos_groupable){ |
||||
|
return this.get_unit_price().toFixed(currency_rounding) + currency_char + '/' + unit.name; |
||||
|
}else{ |
||||
|
return this.get_unit_price().toFixed(currency_rounding) + currency_char; |
||||
|
} |
||||
|
}, |
||||
|
}); |
||||
|
|
||||
|
var OrderSuper = models.Order; |
||||
|
|
||||
|
models.Order = models.Order.extend({ |
||||
|
/** |
||||
|
* @extends add_container from models_and_db.js (module: pos_container) |
||||
|
*/ |
||||
|
add_container: function(container, options){ |
||||
|
// invoke parent object's implementation
|
||||
|
var res = OrderSuper.prototype.add_container.call(this, container, options); |
||||
|
if (container){ |
||||
|
// parent ends with this.select_orderline(this.get_last_orderline());
|
||||
|
var line = this.get_last_orderline(); |
||||
|
this.pos.prepare_text_customer_display('add_container', {'line': line }); |
||||
|
} |
||||
|
return res; |
||||
|
}, |
||||
|
}); |
||||
|
|
||||
|
/** |
||||
|
* Fetch and set currency data when the ProxyStatusWidget starts |
||||
|
*/ |
||||
|
chrome.ProxyStatusWidget.include({ |
||||
|
start: function () { |
||||
|
this._super(); |
||||
|
this.pos.prepare_currency_data_customer_display(); |
||||
|
}, |
||||
|
}); |
||||
|
|
||||
|
screens.OrderWidget.include({ |
||||
|
set_value: function(val) { |
||||
|
var order = this.pos.get_order(); |
||||
|
var selected_orderline = order.get_selected_orderline(); |
||||
|
if (selected_orderline) { |
||||
|
var mode = this.numpad_state.get('mode'); |
||||
|
if( mode === 'quantity' ) { |
||||
|
selected_orderline.qty_manually_set = true; |
||||
|
} |
||||
|
} |
||||
|
this._super(val); |
||||
|
}, |
||||
|
}); |
||||
|
}); |
@ -0,0 +1,10 @@ |
|||||
|
<?xml version="1.0" encoding="utf-8"?> |
||||
|
<odoo> |
||||
|
|
||||
|
<template id="assets" name="pos_customer_display_currency assets" inherit_id="point_of_sale.assets"> |
||||
|
<xpath expr="." position="inside"> |
||||
|
<script type="text/javascript" src="/pos_customer_display_currency/static/src/js/pos_customer_display_currency.js"></script> |
||||
|
</xpath> |
||||
|
</template> |
||||
|
|
||||
|
</odoo> |
@ -0,0 +1,17 @@ |
|||||
|
<?xml version="1.0"?> |
||||
|
<odoo> |
||||
|
<record id="view_pos_config_form" model="ir.ui.view"> |
||||
|
<field name="name">pos_customer_display_currency.pos.config.form</field> |
||||
|
<field name="model">pos.config</field> |
||||
|
<field name="inherit_id" ref="point_of_sale.pos_config_view_form"/> |
||||
|
<field name="arch" type="xml"> |
||||
|
<xpath expr="//field[@name='customer_display_line_length']/.." position="before"> |
||||
|
<div class="row"> |
||||
|
<label for="customer_display_currency_char" class="col-lg-3 o_light_label"/> |
||||
|
<field name="customer_display_currency_char"/> |
||||
|
</div> |
||||
|
</xpath> |
||||
|
</field> |
||||
|
</record> |
||||
|
|
||||
|
</odoo> |
@ -0,0 +1,105 @@ |
|||||
|
=============== |
||||
|
Loyalty Program |
||||
|
=============== |
||||
|
|
||||
|
.. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! |
||||
|
!! This file is generated by oca-gen-addon-readme !! |
||||
|
!! changes will be overwritten. !! |
||||
|
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! |
||||
|
|
||||
|
.. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png |
||||
|
:target: https://odoo-community.org/page/development-status |
||||
|
:alt: Beta |
||||
|
.. |badge2| image:: https://img.shields.io/badge/licence-AGPL--3-blue.png |
||||
|
:target: http://www.gnu.org/licenses/agpl-3.0-standalone.html |
||||
|
:alt: License: AGPL-3 |
||||
|
.. |badge3| image:: https://img.shields.io/badge/github-OCA%2Fpos-lightgray.png?logo=github |
||||
|
:target: https://github.com/OCA/pos/tree/11.0/pos_loyalty |
||||
|
:alt: OCA/pos |
||||
|
.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png |
||||
|
:target: https://translation.odoo-community.org/projects/pos-11-0/pos-11-0-pos_loyalty |
||||
|
:alt: Translate me on Weblate |
||||
|
.. |badge5| image:: https://img.shields.io/badge/runbot-Try%20me-875A7B.png |
||||
|
:target: https://runbot.odoo-community.org/runbot/184/11.0 |
||||
|
:alt: Try me on Runbot |
||||
|
|
||||
|
|badge1| |badge2| |badge3| |badge4| |badge5| |
||||
|
|
||||
|
This module allows you to define a loyalty program in the point of sale, |
||||
|
where the customers earn loyalty points and get rewards. |
||||
|
|
||||
|
This module is a forward-port to v10 of the pos_loyalty module from Odoo's |
||||
|
saas-6 branch. |
||||
|
The functionality was moved to the Enterprise edition in later versions. |
||||
|
|
||||
|
**Table of contents** |
||||
|
|
||||
|
.. contents:: |
||||
|
:local: |
||||
|
|
||||
|
Configuration |
||||
|
============= |
||||
|
|
||||
|
To use this module, you need to: |
||||
|
|
||||
|
* Go to *Point of Sale > Configuration > Loyalty Programs* and define a new loyalty program with specific rules and rewards. |
||||
|
* Assign the loyalty program to the desired Point of Sale. |
||||
|
|
||||
|
Usage |
||||
|
===== |
||||
|
|
||||
|
The Loyalty Program defines rules for acquiring points and rewards on which they can be spent. |
||||
|
|
||||
|
Rules can be defined globally for all products (fields on loyalty.program) and / or rules that are applied only on specific product or PoS category (loyalty.rule records) on a *points per product sold* or *points per currency spent* basis. The specific rules (loyalty.rule) can be defined as cumulative, which means that they will be aggregated with other matching rules (loyalty.rule records and loyalty.program fields). In the case of non-cumulative rules only the points from that one matching rule are used. Additionally, *fixed points per order* can be added which are applied regardless of whether or not cumulative or non-cumulative rules were applied also. |
||||
|
|
||||
|
Rewards can be of three types: |
||||
|
|
||||
|
* *Gift* - give a single unit of product for free |
||||
|
* *Discount* - give a discount to the whole order. It should be added at the end of the order so that the correct total price is used. |
||||
|
* *Resale* - allow for customer to sell back his earned points. These are calculated by setting the price on the Resale product (*resale_product.list_price* * *customer.loyalty_points*) |
||||
|
|
||||
|
All rewards can define how many points they cost (point_cost) and how many are needed so that the customer can become eligable for the reward (minimum_points). for Gift and Discount rewards minimum_points are considered only if they are greater then the point_cost for that reward (minimum_points > point_cost). For Resale products only minimum_points can be used. |
||||
|
|
||||
|
Bug Tracker |
||||
|
=========== |
||||
|
|
||||
|
Bugs are tracked on `GitHub Issues <https://github.com/OCA/pos/issues>`_. |
||||
|
In case of trouble, please check there if your issue has already been reported. |
||||
|
If you spotted it first, help us smashing it by providing a detailed and welcomed |
||||
|
`feedback <https://github.com/OCA/pos/issues/new?body=module:%20pos_loyalty%0Aversion:%2011.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**>`_. |
||||
|
|
||||
|
Do not contact contributors directly about support or help with technical issues. |
||||
|
|
||||
|
Credits |
||||
|
======= |
||||
|
|
||||
|
Authors |
||||
|
~~~~~~~ |
||||
|
|
||||
|
* OpenERP SA |
||||
|
* RGB Consulting SL |
||||
|
* Lambda IS |
||||
|
|
||||
|
Contributors |
||||
|
~~~~~~~~~~~~ |
||||
|
|
||||
|
* RGB Consulting SL (http://www.rgbconsulting.com) |
||||
|
* Forward-port from Odoo SA saas-6 branch |
||||
|
* Kiril Vangelovski <kiril@lambda-is.com> |
||||
|
|
||||
|
Maintainers |
||||
|
~~~~~~~~~~~ |
||||
|
|
||||
|
This module is maintained by the OCA. |
||||
|
|
||||
|
.. image:: https://odoo-community.org/logo.png |
||||
|
:alt: Odoo Community Association |
||||
|
:target: https://odoo-community.org |
||||
|
|
||||
|
OCA, or the Odoo Community Association, is a nonprofit organization whose |
||||
|
mission is to support the collaborative development of Odoo features and |
||||
|
promote its widespread use. |
||||
|
|
||||
|
This module is part of the `OCA/pos <https://github.com/OCA/pos/tree/11.0/pos_loyalty>`_ project on GitHub. |
||||
|
|
||||
|
You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute. |
@ -0,0 +1,3 @@ |
|||||
|
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). |
||||
|
|
||||
|
from . import models |
@ -0,0 +1,36 @@ |
|||||
|
# Copyright 2004-2010 OpenERP SA |
||||
|
# Copyright 2017 RGB Consulting S.L. (https://www.rgbconsulting.com) |
||||
|
# Copyright 2018 Lambda IS DOOEL <https://www.lambda-is.com> |
||||
|
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). |
||||
|
|
||||
|
{ |
||||
|
'name': 'Loyalty Program', |
||||
|
'version': '12.0.1.0.0', |
||||
|
'category': 'Point of Sale', |
||||
|
'license': 'AGPL-3', |
||||
|
'author': "OpenERP SA, " |
||||
|
"RGB Consulting SL, " |
||||
|
"Lambda IS, " |
||||
|
"Odoo Community Association (OCA)", |
||||
|
'website': "https://odoo-community.org/", |
||||
|
'depends': ['point_of_sale'], |
||||
|
'demo': [ |
||||
|
'demo/templates.xml', |
||||
|
], |
||||
|
'data': [ |
||||
|
'security/ir.model.access.csv', |
||||
|
'views/templates.xml', |
||||
|
'views/loyalty_program_view.xml', |
||||
|
'views/loyalty_reward_view.xml', |
||||
|
'views/loyalty_rule_view.xml', |
||||
|
'views/pos_config_view.xml', |
||||
|
'views/pos_order_view.xml', |
||||
|
'views/res_partner_view.xml', |
||||
|
], |
||||
|
|
||||
|
'qweb': [ |
||||
|
'static/src/xml/pos.xml', |
||||
|
], |
||||
|
|
||||
|
'installable': True, |
||||
|
} |
@ -0,0 +1,8 @@ |
|||||
|
<?xml version="1.0" encoding="utf-8"?> |
||||
|
<odoo> |
||||
|
<template id="assets_demo" inherit_id="point_of_sale.assets"> |
||||
|
<xpath expr="." position="inside"> |
||||
|
<script type="text/javascript" src="/pos_loyalty/static/src/js/tests.js"></script> |
||||
|
</xpath> |
||||
|
</template> |
||||
|
</odoo> |
@ -0,0 +1,523 @@ |
|||||
|
# Translation of Odoo Server. |
||||
|
# This file contains the translation of the following modules: |
||||
|
# * pos_loyalty |
||||
|
# |
||||
|
# Translators: |
||||
|
# OCA Transbot <transbot@odoo-community.org>, 2017 |
||||
|
# enjolras <yo@miguelrevilla.com>, 2017 |
||||
|
msgid "" |
||||
|
msgstr "" |
||||
|
"Project-Id-Version: Odoo Server 10.0\n" |
||||
|
"Report-Msgid-Bugs-To: \n" |
||||
|
"POT-Creation-Date: 2018-03-01 02:01+0000\n" |
||||
|
"PO-Revision-Date: 2018-03-01 02:01+0000\n" |
||||
|
"Last-Translator: enjolras <yo@miguelrevilla.com>, 2017\n" |
||||
|
"Language-Team: Spanish (https://www.transifex.com/oca/teams/23907/es/)\n" |
||||
|
"Language: es\n" |
||||
|
"MIME-Version: 1.0\n" |
||||
|
"Content-Type: text/plain; charset=UTF-8\n" |
||||
|
"Content-Transfer-Encoding: \n" |
||||
|
"Plural-Forms: nplurals=2; plural=(n != 1);\n" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,help:pos_loyalty.field_loyalty_program_pp_order |
||||
|
msgid "" |
||||
|
"Amount of loyalty points given to the customer for each point of sale order" |
||||
|
msgstr "" |
||||
|
"Cantidad de puntos de fidelidad añadidos al cliente por cada pedido del " |
||||
|
"punto de venta" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,help:pos_loyalty.field_loyalty_program_pp_product |
||||
|
msgid "Amount of loyalty points given to the customer per product sold" |
||||
|
msgstr "" |
||||
|
"Cantidad de puntos de fidelidad añadidos al cliente por producto vendido" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,help:pos_loyalty.field_loyalty_program_pp_currency |
||||
|
msgid "Amount of loyalty points given to the customer per sold currency" |
||||
|
msgstr "Cantidad de puntos de fidelidad añadidos al cliente por moneda vendida" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,help:pos_loyalty.field_loyalty_rule_pp_currency |
||||
|
msgid "Amount of points earned per currency" |
||||
|
msgstr "Cantidad de puntos ganados por moneda" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,help:pos_loyalty.field_loyalty_rule_pp_product |
||||
|
msgid "Amount of points earned per product" |
||||
|
msgstr "Cantidad de puntos ganados por producto" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: selection:loyalty.rule,type:0 |
||||
|
msgid "Category" |
||||
|
msgstr "Categoría" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.actions.act_window,help:pos_loyalty.loyalty_program_action |
||||
|
msgid "Click create to define a Loyalty Program." |
||||
|
msgstr "Haga clic en crear para definir un Programa de Fidelización" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model,name:pos_loyalty.model_res_partner |
||||
|
msgid "Contact" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,help:pos_loyalty.field_loyalty_reward_point_cost |
||||
|
msgid "Cost of the reward per monetary unit discounted" |
||||
|
msgstr "Coste de la recompensa por unidad monetaria descontada" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_program_create_uid |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_reward_create_uid |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_rule_create_uid |
||||
|
msgid "Created by" |
||||
|
msgstr "Creado por" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_program_create_date |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_reward_create_date |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_rule_create_date |
||||
|
msgid "Created on" |
||||
|
msgstr "Creado el" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_rule_cumulative |
||||
|
msgid "Cumulative" |
||||
|
msgstr "Acumulativo" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_reward_discount |
||||
|
#: selection:loyalty.reward,type:0 |
||||
|
msgid "Discount" |
||||
|
msgstr "Descuento" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_reward_discount_product_id |
||||
|
msgid "Discount Product" |
||||
|
msgstr "Producto de descuento" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_reward_discount_max |
||||
|
msgid "Discount limit" |
||||
|
msgstr "Límite de descuento" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: code:addons/pos_loyalty/models/loyalty_reward.py:64 |
||||
|
#, python-format |
||||
|
msgid "Discount product field is mandatory for discount rewards" |
||||
|
msgstr "" |
||||
|
"El campo Producto de descuento es obligatorio para las recompensas de tipo " |
||||
|
"descuento." |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_program_display_name |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_reward_display_name |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_rule_display_name |
||||
|
msgid "Display Name" |
||||
|
msgstr "Nombre a mostrar" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: selection:loyalty.reward,type:0 |
||||
|
msgid "Gift" |
||||
|
msgstr "Regalo" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_reward_gift_product_id |
||||
|
msgid "Gift Product" |
||||
|
msgstr "Producto de regalo" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: code:addons/pos_loyalty/models/loyalty_reward.py:57 |
||||
|
#, python-format |
||||
|
msgid "Gift product field is mandatory for gift rewards" |
||||
|
msgstr "" |
||||
|
"El campo Producto de regalo es obligatorio para las recompensas de tipo " |
||||
|
"regalo" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_program_id |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_reward_id |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_rule_id |
||||
|
msgid "ID" |
||||
|
msgstr "ID" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_program___last_update |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_reward___last_update |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_rule___last_update |
||||
|
msgid "Last Modified on" |
||||
|
msgstr "Última modificación el" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_program_write_uid |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_reward_write_uid |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_rule_write_uid |
||||
|
msgid "Last Updated by" |
||||
|
msgstr "Última actualización por" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_program_write_date |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_reward_write_date |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_rule_write_date |
||||
|
msgid "Last Updated on" |
||||
|
msgstr "Última actualización el" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model,name:pos_loyalty.model_pos_order_line |
||||
|
#, fuzzy |
||||
|
msgid "Lines of Point of Sale Orders" |
||||
|
msgstr "Pedidos del TPV" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_pos_order_loyalty_points |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_res_partner_loyalty_points |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_res_users_loyalty_points |
||||
|
msgid "Loyalty Points" |
||||
|
msgstr "Puntos de fidelidad" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_reward_loyalty_program_id |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_rule_loyalty_program_id |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_pos_config_loyalty_id |
||||
|
#: model:ir.ui.view,arch_db:pos_loyalty.loyalty_program_form_view |
||||
|
msgid "Loyalty Program" |
||||
|
msgstr "Programa de fidelización" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.ui.view,arch_db:pos_loyalty.pos_config_view_form |
||||
|
#, fuzzy |
||||
|
msgid "Loyalty Program (OCA)" |
||||
|
msgstr "Programa de fidelización" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_program_name |
||||
|
msgid "Loyalty Program Name" |
||||
|
msgstr "Nombre programa de fidelización" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.actions.act_window,name:pos_loyalty.loyalty_program_action |
||||
|
#: model:ir.ui.menu,name:pos_loyalty.loyalty_program_menu |
||||
|
#: model:ir.ui.view,arch_db:pos_loyalty.loyalty_program_tree_view |
||||
|
#: model:ir.ui.view,arch_db:pos_loyalty.partner_property_form_view |
||||
|
#: model:ir.ui.view,arch_db:pos_loyalty.pos_order_form_view |
||||
|
msgid "Loyalty Programs" |
||||
|
msgstr "Programas de fidelización" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.actions.act_window,help:pos_loyalty.loyalty_program_action |
||||
|
msgid "" |
||||
|
"Loyalty Programs allow you customers to earn points\n" |
||||
|
" and rewards when purchasing from your shops." |
||||
|
msgstr "" |
||||
|
"Los programas de fidelización le permiten a los clientes ganar puntos\n" |
||||
|
" y recompensas al comprar en tus tiendas." |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.ui.view,arch_db:pos_loyalty.loyalty_reward_form_view |
||||
|
msgid "Loyalty Reward" |
||||
|
msgstr "Recompensa de fidelización" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.ui.view,arch_db:pos_loyalty.loyalty_rule_form_view |
||||
|
msgid "Loyalty Rule" |
||||
|
msgstr "Regla de fidelización" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,help:pos_loyalty.field_loyalty_program_rounding |
||||
|
msgid "Loyalty point amounts will be rounded to multiples of this value" |
||||
|
msgstr "Los puntos de fidelidad se redondearán a múltiplos de este valor" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.ui.view,arch_db:pos_loyalty.pos_config_view_form |
||||
|
#, fuzzy |
||||
|
msgid "Loyalty program that will be available in this PoS" |
||||
|
msgstr "El programa de fidelización al que pertenece esta regla" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,help:pos_loyalty.field_loyalty_reward_discount_max |
||||
|
msgid "Maximum discounted amount allowed forthis discount reward" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_reward_minimum_points |
||||
|
msgid "Minimum Points" |
||||
|
msgstr "Puntos mínimos" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,help:pos_loyalty.field_loyalty_reward_minimum_points |
||||
|
msgid "" |
||||
|
"Minimum amount of points the customer must have to qualify for this reward" |
||||
|
msgstr "Cantidad mínima de puntos de cliente para acceder a esta recompensa" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#. openerp-web |
||||
|
#: code:addons/pos_loyalty/static/src/js/pos.js:379 |
||||
|
#, python-format |
||||
|
msgid "No Rewards Available" |
||||
|
msgstr "No hay recompensas disponibles" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#. openerp-web |
||||
|
#: code:addons/pos_loyalty/static/src/js/pos.js:393 |
||||
|
#, python-format |
||||
|
msgid "Please select a reward" |
||||
|
msgstr "Selecciona una recompensa" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_reward_point_cost |
||||
|
msgid "Point Cost" |
||||
|
msgstr "Coste Puntos" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_reward_point_product_id |
||||
|
msgid "Point Product" |
||||
|
msgstr "Producto Punto" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model,name:pos_loyalty.model_pos_order |
||||
|
msgid "Point of Sale Orders" |
||||
|
msgstr "Pedidos del TPV" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: code:addons/pos_loyalty/models/loyalty_reward.py:72 |
||||
|
#, python-format |
||||
|
msgid "Point product field is mandatory for point resale rewards" |
||||
|
msgstr "" |
||||
|
"El campo Producto Punto es obligatorio para recompensas de reventa de puntos" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#. openerp-web |
||||
|
#: code:addons/pos_loyalty/static/src/xml/pos.xml:6 |
||||
|
#: code:addons/pos_loyalty/static/src/xml/pos.xml:71 |
||||
|
#: code:addons/pos_loyalty/static/src/xml/pos.xml:81 |
||||
|
#, python-format |
||||
|
msgid "Points" |
||||
|
msgstr "Puntos" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_program_rounding |
||||
|
msgid "Points Rounding" |
||||
|
msgstr "Redondeo Puntos" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#. openerp-web |
||||
|
#: code:addons/pos_loyalty/static/src/xml/pos.xml:57 |
||||
|
#, python-format |
||||
|
msgid "Points Spent" |
||||
|
msgstr "Puntos Gastados" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#. openerp-web |
||||
|
#: code:addons/pos_loyalty/static/src/xml/pos.xml:54 |
||||
|
#, python-format |
||||
|
msgid "Points Won" |
||||
|
msgstr "Puntos Ganados" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_program_pp_currency |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_rule_pp_currency |
||||
|
msgid "Points per currency" |
||||
|
msgstr "Puntos por moneda" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_program_pp_order |
||||
|
msgid "Points per order" |
||||
|
msgstr "Puntos por venta" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_program_pp_product |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_rule_pp_product |
||||
|
msgid "Points per product" |
||||
|
msgstr "Puntos por producto" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: selection:loyalty.rule,type:0 |
||||
|
msgid "Product" |
||||
|
msgstr "Producto" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,help:pos_loyalty.field_loyalty_reward_point_product_id |
||||
|
msgid "Product that represents a point that is sold by the customer" |
||||
|
msgstr "Producto que representa un punto vendido por el cliente" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: selection:loyalty.reward,type:0 |
||||
|
msgid "Resale" |
||||
|
msgstr "Reventa" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_reward_name |
||||
|
msgid "Reward Name" |
||||
|
msgstr "Nombre recompensa" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.ui.view,arch_db:pos_loyalty.loyalty_program_form_view |
||||
|
msgid "Reward the customer with gifts or discounts for loyalty points" |
||||
|
msgstr "" |
||||
|
"Recompensar al cliente con regalos o descuentos por puntos de fidelidad" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#. openerp-web |
||||
|
#: code:addons/pos_loyalty/static/src/xml/pos.xml:25 |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_program_reward_ids |
||||
|
#: model:ir.ui.view,arch_db:pos_loyalty.loyalty_program_form_view |
||||
|
#, python-format |
||||
|
msgid "Rewards" |
||||
|
msgstr "Recompensas" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_rule_name |
||||
|
msgid "Rule Name" |
||||
|
msgstr "Nombre de regla" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_program_rule_ids |
||||
|
#: model:ir.ui.view,arch_db:pos_loyalty.loyalty_program_form_view |
||||
|
msgid "Rules" |
||||
|
msgstr "Reglas" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.ui.view,arch_db:pos_loyalty.loyalty_program_form_view |
||||
|
msgid "" |
||||
|
"Rules define how loyalty points are earned for specific products or " |
||||
|
"categories" |
||||
|
msgstr "" |
||||
|
"Las reglas definen cómo se obtienen puntos de fidelidad para productos o " |
||||
|
"categorías específicos" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_rule_category_id |
||||
|
msgid "Target Category" |
||||
|
msgstr "Categoría afectada" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_rule_product_id |
||||
|
msgid "Target Product" |
||||
|
msgstr "Producto afectado" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,help:pos_loyalty.field_loyalty_reward_loyalty_program_id |
||||
|
msgid "The Loyalty Program this reward belongs to" |
||||
|
msgstr "El programa de fidelización al que pertenece esta recompensa" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,help:pos_loyalty.field_loyalty_rule_loyalty_program_id |
||||
|
msgid "The Loyalty Program this rule belongs to" |
||||
|
msgstr "El programa de fidelización al que pertenece esta regla" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,help:pos_loyalty.field_pos_order_loyalty_points |
||||
|
msgid "The amount of Loyalty points awarded to the customer with this order" |
||||
|
msgstr "" |
||||
|
"La cantidad de puntos de fidelidad que el cliente obtiene con este pedido" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,help:pos_loyalty.field_loyalty_rule_category_id |
||||
|
msgid "The category affected by this rule" |
||||
|
msgstr "La categoría afectada por esta regla" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,help:pos_loyalty.field_loyalty_rule_type |
||||
|
msgid "The concept this rule applies to" |
||||
|
msgstr "El concepto al que aplica esta regla" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,help:pos_loyalty.field_loyalty_reward_discount |
||||
|
msgid "The discount percentage" |
||||
|
msgstr "El porcentaje de descuento" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,help:pos_loyalty.field_res_partner_loyalty_points |
||||
|
#: model:ir.model.fields,help:pos_loyalty.field_res_users_loyalty_points |
||||
|
msgid "The loyalty points the user won as part of a Loyalty Program" |
||||
|
msgstr "" |
||||
|
"Los puntos de fidelidad que el usuario ganó como parte de un Programa de " |
||||
|
"Fidelización" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,help:pos_loyalty.field_pos_config_loyalty_id |
||||
|
msgid "The loyalty program used by this Point of Sale" |
||||
|
msgstr "El programa de fidelización utilizado en este Punto de Venta" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,help:pos_loyalty.field_loyalty_rule_cumulative |
||||
|
msgid "" |
||||
|
"The points from this rule will be added to points won from other rules with " |
||||
|
"the same concept" |
||||
|
msgstr "" |
||||
|
"Los puntos de esta regla se añadirán a los puntos ganados en otras reglas " |
||||
|
"con el mismo concepto" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,help:pos_loyalty.field_loyalty_rule_product_id |
||||
|
msgid "The product affected by this rule" |
||||
|
msgstr "El producto afectado por esta regla" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,help:pos_loyalty.field_loyalty_reward_gift_product_id |
||||
|
msgid "The product given as a reward" |
||||
|
msgstr "El producto utilizado como recompensa" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,help:pos_loyalty.field_loyalty_reward_discount_product_id |
||||
|
msgid "The product used to apply discounts" |
||||
|
msgstr "El producto utilizado para aplicar descuentos" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#. openerp-web |
||||
|
#: code:addons/pos_loyalty/static/src/js/pos.js:380 |
||||
|
#, python-format |
||||
|
msgid "" |
||||
|
"There are no rewards available for this customer as part of the loyalty " |
||||
|
"program" |
||||
|
msgstr "" |
||||
|
"No hay recompensas disponibles para este cliente como parte de este programa " |
||||
|
"de fidelización" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#. openerp-web |
||||
|
#: code:addons/pos_loyalty/static/src/xml/pos.xml:60 |
||||
|
#, python-format |
||||
|
msgid "Total Points" |
||||
|
msgstr "Total Puntos" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_reward_type |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_rule_type |
||||
|
msgid "Type" |
||||
|
msgstr "Tipo" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,help:pos_loyalty.field_loyalty_reward_type |
||||
|
msgid "Type of the reward" |
||||
|
msgstr "Tipo de recompensa" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.ui.view,arch_db:pos_loyalty.pos_config_view_form |
||||
|
msgid "abc" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model,name:pos_loyalty.model_loyalty_program |
||||
|
msgid "loyalty.program" |
||||
|
msgstr "loyalty.program" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model,name:pos_loyalty.model_loyalty_reward |
||||
|
msgid "loyalty.reward" |
||||
|
msgstr "loyalty.reward" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model,name:pos_loyalty.model_loyalty_rule |
||||
|
msgid "loyalty.rule" |
||||
|
msgstr "loyalty.rule" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model,name:pos_loyalty.model_pos_config |
||||
|
msgid "pos.config" |
||||
|
msgstr "pos.config" |
||||
|
|
||||
|
#~ msgid "Partner" |
||||
|
#~ msgstr "Empresa" |
@ -0,0 +1,504 @@ |
|||||
|
# Translation of Odoo Server. |
||||
|
# This file contains the translation of the following modules: |
||||
|
# * pos_loyalty |
||||
|
# |
||||
|
# Translators: |
||||
|
# leemannd <denis.leemann@camptocamp.com>, 2017 |
||||
|
# OCA Transbot <transbot@odoo-community.org>, 2018 |
||||
|
msgid "" |
||||
|
msgstr "" |
||||
|
"Project-Id-Version: Odoo Server 10.0\n" |
||||
|
"Report-Msgid-Bugs-To: \n" |
||||
|
"POT-Creation-Date: 2018-03-01 02:01+0000\n" |
||||
|
"PO-Revision-Date: 2018-03-01 02:01+0000\n" |
||||
|
"Last-Translator: OCA Transbot <transbot@odoo-community.org>, 2018\n" |
||||
|
"Language-Team: French (https://www.transifex.com/oca/teams/23907/fr/)\n" |
||||
|
"Language: fr\n" |
||||
|
"MIME-Version: 1.0\n" |
||||
|
"Content-Type: text/plain; charset=UTF-8\n" |
||||
|
"Content-Transfer-Encoding: \n" |
||||
|
"Plural-Forms: nplurals=2; plural=(n > 1);\n" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,help:pos_loyalty.field_loyalty_program_pp_order |
||||
|
msgid "" |
||||
|
"Amount of loyalty points given to the customer for each point of sale order" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,help:pos_loyalty.field_loyalty_program_pp_product |
||||
|
msgid "Amount of loyalty points given to the customer per product sold" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,help:pos_loyalty.field_loyalty_program_pp_currency |
||||
|
msgid "Amount of loyalty points given to the customer per sold currency" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,help:pos_loyalty.field_loyalty_rule_pp_currency |
||||
|
msgid "Amount of points earned per currency" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,help:pos_loyalty.field_loyalty_rule_pp_product |
||||
|
msgid "Amount of points earned per product" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: selection:loyalty.rule,type:0 |
||||
|
msgid "Category" |
||||
|
msgstr "Catégorie" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.actions.act_window,help:pos_loyalty.loyalty_program_action |
||||
|
msgid "Click create to define a Loyalty Program." |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model,name:pos_loyalty.model_res_partner |
||||
|
msgid "Contact" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,help:pos_loyalty.field_loyalty_reward_point_cost |
||||
|
msgid "Cost of the reward per monetary unit discounted" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_program_create_uid |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_reward_create_uid |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_rule_create_uid |
||||
|
msgid "Created by" |
||||
|
msgstr "Créé par" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_program_create_date |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_reward_create_date |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_rule_create_date |
||||
|
msgid "Created on" |
||||
|
msgstr "Créé le" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_rule_cumulative |
||||
|
msgid "Cumulative" |
||||
|
msgstr "Cumulatif" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_reward_discount |
||||
|
#: selection:loyalty.reward,type:0 |
||||
|
msgid "Discount" |
||||
|
msgstr "Rabaias" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_reward_discount_product_id |
||||
|
msgid "Discount Product" |
||||
|
msgstr "Produit Soldé" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_reward_discount_max |
||||
|
msgid "Discount limit" |
||||
|
msgstr "Limite de Rabais" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: code:addons/pos_loyalty/models/loyalty_reward.py:64 |
||||
|
#, python-format |
||||
|
msgid "Discount product field is mandatory for discount rewards" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_program_display_name |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_reward_display_name |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_rule_display_name |
||||
|
msgid "Display Name" |
||||
|
msgstr "Nom Affiché" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: selection:loyalty.reward,type:0 |
||||
|
msgid "Gift" |
||||
|
msgstr "Cadeau" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_reward_gift_product_id |
||||
|
msgid "Gift Product" |
||||
|
msgstr "Produit Cadeau" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: code:addons/pos_loyalty/models/loyalty_reward.py:57 |
||||
|
#, python-format |
||||
|
msgid "Gift product field is mandatory for gift rewards" |
||||
|
msgstr "" |
||||
|
"Le champs 'produit cadeau' est nécessaire pour les cadeau de récompense" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_program_id |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_reward_id |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_rule_id |
||||
|
msgid "ID" |
||||
|
msgstr "ID" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_program___last_update |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_reward___last_update |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_rule___last_update |
||||
|
msgid "Last Modified on" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_program_write_uid |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_reward_write_uid |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_rule_write_uid |
||||
|
msgid "Last Updated by" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_program_write_date |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_reward_write_date |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_rule_write_date |
||||
|
msgid "Last Updated on" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model,name:pos_loyalty.model_pos_order_line |
||||
|
msgid "Lines of Point of Sale Orders" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_pos_order_loyalty_points |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_res_partner_loyalty_points |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_res_users_loyalty_points |
||||
|
msgid "Loyalty Points" |
||||
|
msgstr "Points de fidélité" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_reward_loyalty_program_id |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_rule_loyalty_program_id |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_pos_config_loyalty_id |
||||
|
#: model:ir.ui.view,arch_db:pos_loyalty.loyalty_program_form_view |
||||
|
msgid "Loyalty Program" |
||||
|
msgstr "Programme de Fidélité" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.ui.view,arch_db:pos_loyalty.pos_config_view_form |
||||
|
#, fuzzy |
||||
|
msgid "Loyalty Program (OCA)" |
||||
|
msgstr "Programme de Fidélité" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_program_name |
||||
|
msgid "Loyalty Program Name" |
||||
|
msgstr "Nom du Programme de Fidélité" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.actions.act_window,name:pos_loyalty.loyalty_program_action |
||||
|
#: model:ir.ui.menu,name:pos_loyalty.loyalty_program_menu |
||||
|
#: model:ir.ui.view,arch_db:pos_loyalty.loyalty_program_tree_view |
||||
|
#: model:ir.ui.view,arch_db:pos_loyalty.partner_property_form_view |
||||
|
#: model:ir.ui.view,arch_db:pos_loyalty.pos_order_form_view |
||||
|
msgid "Loyalty Programs" |
||||
|
msgstr "Progammes de Fidélité" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.actions.act_window,help:pos_loyalty.loyalty_program_action |
||||
|
msgid "" |
||||
|
"Loyalty Programs allow you customers to earn points\n" |
||||
|
" and rewards when purchasing from your shops." |
||||
|
msgstr "" |
||||
|
"Les programmes de fidélité permettent aux clients de gagner des points\n" |
||||
|
"et des cadeaux lors de leurs achats sur vos sites internet." |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.ui.view,arch_db:pos_loyalty.loyalty_reward_form_view |
||||
|
msgid "Loyalty Reward" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.ui.view,arch_db:pos_loyalty.loyalty_rule_form_view |
||||
|
msgid "Loyalty Rule" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,help:pos_loyalty.field_loyalty_program_rounding |
||||
|
msgid "Loyalty point amounts will be rounded to multiples of this value" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.ui.view,arch_db:pos_loyalty.pos_config_view_form |
||||
|
msgid "Loyalty program that will be available in this PoS" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,help:pos_loyalty.field_loyalty_reward_discount_max |
||||
|
msgid "Maximum discounted amount allowed forthis discount reward" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_reward_minimum_points |
||||
|
msgid "Minimum Points" |
||||
|
msgstr "Points Minimum" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,help:pos_loyalty.field_loyalty_reward_minimum_points |
||||
|
msgid "" |
||||
|
"Minimum amount of points the customer must have to qualify for this reward" |
||||
|
msgstr "Le minimum de points requis pour avoir le droit à cette récompense" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#. openerp-web |
||||
|
#: code:addons/pos_loyalty/static/src/js/pos.js:379 |
||||
|
#, python-format |
||||
|
msgid "No Rewards Available" |
||||
|
msgstr "Pas de récompenses disponible" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#. openerp-web |
||||
|
#: code:addons/pos_loyalty/static/src/js/pos.js:393 |
||||
|
#, python-format |
||||
|
msgid "Please select a reward" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_reward_point_cost |
||||
|
msgid "Point Cost" |
||||
|
msgstr "Coût en points" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_reward_point_product_id |
||||
|
msgid "Point Product" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model,name:pos_loyalty.model_pos_order |
||||
|
msgid "Point of Sale Orders" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: code:addons/pos_loyalty/models/loyalty_reward.py:72 |
||||
|
#, python-format |
||||
|
msgid "Point product field is mandatory for point resale rewards" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#. openerp-web |
||||
|
#: code:addons/pos_loyalty/static/src/xml/pos.xml:6 |
||||
|
#: code:addons/pos_loyalty/static/src/xml/pos.xml:71 |
||||
|
#: code:addons/pos_loyalty/static/src/xml/pos.xml:81 |
||||
|
#, python-format |
||||
|
msgid "Points" |
||||
|
msgstr "Points" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_program_rounding |
||||
|
msgid "Points Rounding" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#. openerp-web |
||||
|
#: code:addons/pos_loyalty/static/src/xml/pos.xml:57 |
||||
|
#, python-format |
||||
|
msgid "Points Spent" |
||||
|
msgstr "Points dépensés" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#. openerp-web |
||||
|
#: code:addons/pos_loyalty/static/src/xml/pos.xml:54 |
||||
|
#, python-format |
||||
|
msgid "Points Won" |
||||
|
msgstr "Points Gagnés" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_program_pp_currency |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_rule_pp_currency |
||||
|
msgid "Points per currency" |
||||
|
msgstr "Points par devise" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_program_pp_order |
||||
|
msgid "Points per order" |
||||
|
msgstr "Points par commande" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_program_pp_product |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_rule_pp_product |
||||
|
msgid "Points per product" |
||||
|
msgstr "Points par produit" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: selection:loyalty.rule,type:0 |
||||
|
msgid "Product" |
||||
|
msgstr "Produit" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,help:pos_loyalty.field_loyalty_reward_point_product_id |
||||
|
msgid "Product that represents a point that is sold by the customer" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: selection:loyalty.reward,type:0 |
||||
|
msgid "Resale" |
||||
|
msgstr "Revente" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_reward_name |
||||
|
msgid "Reward Name" |
||||
|
msgstr "Nom de Récompense" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.ui.view,arch_db:pos_loyalty.loyalty_program_form_view |
||||
|
msgid "Reward the customer with gifts or discounts for loyalty points" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#. openerp-web |
||||
|
#: code:addons/pos_loyalty/static/src/xml/pos.xml:25 |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_program_reward_ids |
||||
|
#: model:ir.ui.view,arch_db:pos_loyalty.loyalty_program_form_view |
||||
|
#, python-format |
||||
|
msgid "Rewards" |
||||
|
msgstr "Récompenses" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_rule_name |
||||
|
msgid "Rule Name" |
||||
|
msgstr "Nom de Règle" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_program_rule_ids |
||||
|
#: model:ir.ui.view,arch_db:pos_loyalty.loyalty_program_form_view |
||||
|
msgid "Rules" |
||||
|
msgstr "Règles" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.ui.view,arch_db:pos_loyalty.loyalty_program_form_view |
||||
|
msgid "" |
||||
|
"Rules define how loyalty points are earned for specific products or " |
||||
|
"categories" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_rule_category_id |
||||
|
msgid "Target Category" |
||||
|
msgstr "Catégorie cible" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_rule_product_id |
||||
|
msgid "Target Product" |
||||
|
msgstr "Produit Cible" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,help:pos_loyalty.field_loyalty_reward_loyalty_program_id |
||||
|
msgid "The Loyalty Program this reward belongs to" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,help:pos_loyalty.field_loyalty_rule_loyalty_program_id |
||||
|
msgid "The Loyalty Program this rule belongs to" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,help:pos_loyalty.field_pos_order_loyalty_points |
||||
|
msgid "The amount of Loyalty points awarded to the customer with this order" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,help:pos_loyalty.field_loyalty_rule_category_id |
||||
|
msgid "The category affected by this rule" |
||||
|
msgstr "La catégorie affectée par la règle" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,help:pos_loyalty.field_loyalty_rule_type |
||||
|
msgid "The concept this rule applies to" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,help:pos_loyalty.field_loyalty_reward_discount |
||||
|
msgid "The discount percentage" |
||||
|
msgstr "Le pourcentage de rabais" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,help:pos_loyalty.field_res_partner_loyalty_points |
||||
|
#: model:ir.model.fields,help:pos_loyalty.field_res_users_loyalty_points |
||||
|
msgid "The loyalty points the user won as part of a Loyalty Program" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,help:pos_loyalty.field_pos_config_loyalty_id |
||||
|
msgid "The loyalty program used by this Point of Sale" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,help:pos_loyalty.field_loyalty_rule_cumulative |
||||
|
msgid "" |
||||
|
"The points from this rule will be added to points won from other rules with " |
||||
|
"the same concept" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,help:pos_loyalty.field_loyalty_rule_product_id |
||||
|
msgid "The product affected by this rule" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,help:pos_loyalty.field_loyalty_reward_gift_product_id |
||||
|
msgid "The product given as a reward" |
||||
|
msgstr "Le produit est donné en guise de récompense" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,help:pos_loyalty.field_loyalty_reward_discount_product_id |
||||
|
msgid "The product used to apply discounts" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#. openerp-web |
||||
|
#: code:addons/pos_loyalty/static/src/js/pos.js:380 |
||||
|
#, python-format |
||||
|
msgid "" |
||||
|
"There are no rewards available for this customer as part of the loyalty " |
||||
|
"program" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#. openerp-web |
||||
|
#: code:addons/pos_loyalty/static/src/xml/pos.xml:60 |
||||
|
#, python-format |
||||
|
msgid "Total Points" |
||||
|
msgstr "Points Totaux" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_reward_type |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_rule_type |
||||
|
msgid "Type" |
||||
|
msgstr "Type" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,help:pos_loyalty.field_loyalty_reward_type |
||||
|
msgid "Type of the reward" |
||||
|
msgstr "Type de récompense" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.ui.view,arch_db:pos_loyalty.pos_config_view_form |
||||
|
msgid "abc" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model,name:pos_loyalty.model_loyalty_program |
||||
|
msgid "loyalty.program" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model,name:pos_loyalty.model_loyalty_reward |
||||
|
msgid "loyalty.reward" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model,name:pos_loyalty.model_loyalty_rule |
||||
|
msgid "loyalty.rule" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model,name:pos_loyalty.model_pos_config |
||||
|
msgid "pos.config" |
||||
|
msgstr "pos.config" |
||||
|
|
||||
|
#~ msgid "Partner" |
||||
|
#~ msgstr "Partner" |
@ -0,0 +1,498 @@ |
|||||
|
# Translation of Odoo Server. |
||||
|
# This file contains the translation of the following modules: |
||||
|
# * pos_loyalty |
||||
|
# |
||||
|
# Translators: |
||||
|
# Bole <bole@dajmi5.com>, 2017 |
||||
|
msgid "" |
||||
|
msgstr "" |
||||
|
"Project-Id-Version: Odoo Server 10.0\n" |
||||
|
"Report-Msgid-Bugs-To: \n" |
||||
|
"POT-Creation-Date: 2017-07-12 02:44+0000\n" |
||||
|
"PO-Revision-Date: 2017-07-12 02:44+0000\n" |
||||
|
"Last-Translator: Bole <bole@dajmi5.com>, 2017\n" |
||||
|
"Language-Team: Croatian (Croatia) (https://www.transifex.com/oca/teams/23907/" |
||||
|
"hr_HR/)\n" |
||||
|
"Language: hr_HR\n" |
||||
|
"MIME-Version: 1.0\n" |
||||
|
"Content-Type: text/plain; charset=UTF-8\n" |
||||
|
"Content-Transfer-Encoding: \n" |
||||
|
"Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && n" |
||||
|
"%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,help:pos_loyalty.field_loyalty_program_pp_order |
||||
|
msgid "" |
||||
|
"Amount of loyalty points given to the customer for each point of sale order" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,help:pos_loyalty.field_loyalty_program_pp_product |
||||
|
msgid "Amount of loyalty points given to the customer per product sold" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,help:pos_loyalty.field_loyalty_program_pp_currency |
||||
|
msgid "Amount of loyalty points given to the customer per sold currency" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,help:pos_loyalty.field_loyalty_rule_pp_currency |
||||
|
msgid "Amount of points earned per currency" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,help:pos_loyalty.field_loyalty_rule_pp_product |
||||
|
msgid "Amount of points earned per product" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: selection:loyalty.rule,type:0 |
||||
|
msgid "Category" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.actions.act_window,help:pos_loyalty.loyalty_program_action |
||||
|
msgid "Click create to define a Loyalty Program." |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model,name:pos_loyalty.model_res_partner |
||||
|
msgid "Contact" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,help:pos_loyalty.field_loyalty_reward_point_cost |
||||
|
msgid "Cost of the reward per monetary unit discounted" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_program_create_uid |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_reward_create_uid |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_rule_create_uid |
||||
|
msgid "Created by" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_program_create_date |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_reward_create_date |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_rule_create_date |
||||
|
msgid "Created on" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_rule_cumulative |
||||
|
msgid "Cumulative" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_reward_discount |
||||
|
#: selection:loyalty.reward,type:0 |
||||
|
msgid "Discount" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_reward_discount_product_id |
||||
|
msgid "Discount Product" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_reward_discount_max |
||||
|
msgid "Discount limit" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: code:addons/pos_loyalty/models/loyalty_reward.py:64 |
||||
|
#, python-format |
||||
|
msgid "Discount product field is mandatory for discount rewards" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_program_display_name |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_reward_display_name |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_rule_display_name |
||||
|
msgid "Display Name" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: selection:loyalty.reward,type:0 |
||||
|
msgid "Gift" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_reward_gift_product_id |
||||
|
msgid "Gift Product" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: code:addons/pos_loyalty/models/loyalty_reward.py:57 |
||||
|
#, python-format |
||||
|
msgid "Gift product field is mandatory for gift rewards" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_program_id |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_reward_id |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_rule_id |
||||
|
msgid "ID" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_program___last_update |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_reward___last_update |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_rule___last_update |
||||
|
msgid "Last Modified on" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_program_write_uid |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_reward_write_uid |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_rule_write_uid |
||||
|
msgid "Last Updated by" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_program_write_date |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_reward_write_date |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_rule_write_date |
||||
|
msgid "Last Updated on" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model,name:pos_loyalty.model_pos_order_line |
||||
|
msgid "Lines of Point of Sale Orders" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_pos_order_loyalty_points |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_res_partner_loyalty_points |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_res_users_loyalty_points |
||||
|
msgid "Loyalty Points" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_reward_loyalty_program_id |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_rule_loyalty_program_id |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_pos_config_loyalty_id |
||||
|
#: model:ir.ui.view,arch_db:pos_loyalty.loyalty_program_form_view |
||||
|
msgid "Loyalty Program" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.ui.view,arch_db:pos_loyalty.pos_config_view_form |
||||
|
msgid "Loyalty Program (OCA)" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_program_name |
||||
|
msgid "Loyalty Program Name" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.actions.act_window,name:pos_loyalty.loyalty_program_action |
||||
|
#: model:ir.ui.menu,name:pos_loyalty.loyalty_program_menu |
||||
|
#: model:ir.ui.view,arch_db:pos_loyalty.loyalty_program_tree_view |
||||
|
#: model:ir.ui.view,arch_db:pos_loyalty.partner_property_form_view |
||||
|
#: model:ir.ui.view,arch_db:pos_loyalty.pos_order_form_view |
||||
|
msgid "Loyalty Programs" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.actions.act_window,help:pos_loyalty.loyalty_program_action |
||||
|
msgid "" |
||||
|
"Loyalty Programs allow you customers to earn points\n" |
||||
|
" and rewards when purchasing from your shops." |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.ui.view,arch_db:pos_loyalty.loyalty_reward_form_view |
||||
|
msgid "Loyalty Reward" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.ui.view,arch_db:pos_loyalty.loyalty_rule_form_view |
||||
|
msgid "Loyalty Rule" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,help:pos_loyalty.field_loyalty_program_rounding |
||||
|
msgid "Loyalty point amounts will be rounded to multiples of this value" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.ui.view,arch_db:pos_loyalty.pos_config_view_form |
||||
|
msgid "Loyalty program that will be available in this PoS" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,help:pos_loyalty.field_loyalty_reward_discount_max |
||||
|
msgid "Maximum discounted amount allowed forthis discount reward" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_reward_minimum_points |
||||
|
msgid "Minimum Points" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,help:pos_loyalty.field_loyalty_reward_minimum_points |
||||
|
msgid "" |
||||
|
"Minimum amount of points the customer must have to qualify for this reward" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#. openerp-web |
||||
|
#: code:addons/pos_loyalty/static/src/js/pos.js:379 |
||||
|
#, python-format |
||||
|
msgid "No Rewards Available" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#. openerp-web |
||||
|
#: code:addons/pos_loyalty/static/src/js/pos.js:393 |
||||
|
#, python-format |
||||
|
msgid "Please select a reward" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_reward_point_cost |
||||
|
msgid "Point Cost" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_reward_point_product_id |
||||
|
msgid "Point Product" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model,name:pos_loyalty.model_pos_order |
||||
|
msgid "Point of Sale Orders" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: code:addons/pos_loyalty/models/loyalty_reward.py:72 |
||||
|
#, python-format |
||||
|
msgid "Point product field is mandatory for point resale rewards" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#. openerp-web |
||||
|
#: code:addons/pos_loyalty/static/src/xml/pos.xml:6 |
||||
|
#: code:addons/pos_loyalty/static/src/xml/pos.xml:71 |
||||
|
#: code:addons/pos_loyalty/static/src/xml/pos.xml:81 |
||||
|
#, python-format |
||||
|
msgid "Points" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_program_rounding |
||||
|
msgid "Points Rounding" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#. openerp-web |
||||
|
#: code:addons/pos_loyalty/static/src/xml/pos.xml:57 |
||||
|
#, python-format |
||||
|
msgid "Points Spent" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#. openerp-web |
||||
|
#: code:addons/pos_loyalty/static/src/xml/pos.xml:54 |
||||
|
#, python-format |
||||
|
msgid "Points Won" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_program_pp_currency |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_rule_pp_currency |
||||
|
msgid "Points per currency" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_program_pp_order |
||||
|
msgid "Points per order" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_program_pp_product |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_rule_pp_product |
||||
|
msgid "Points per product" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: selection:loyalty.rule,type:0 |
||||
|
msgid "Product" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,help:pos_loyalty.field_loyalty_reward_point_product_id |
||||
|
msgid "Product that represents a point that is sold by the customer" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: selection:loyalty.reward,type:0 |
||||
|
msgid "Resale" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_reward_name |
||||
|
msgid "Reward Name" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.ui.view,arch_db:pos_loyalty.loyalty_program_form_view |
||||
|
msgid "Reward the customer with gifts or discounts for loyalty points" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#. openerp-web |
||||
|
#: code:addons/pos_loyalty/static/src/xml/pos.xml:25 |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_program_reward_ids |
||||
|
#: model:ir.ui.view,arch_db:pos_loyalty.loyalty_program_form_view |
||||
|
#, python-format |
||||
|
msgid "Rewards" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_rule_name |
||||
|
msgid "Rule Name" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_program_rule_ids |
||||
|
#: model:ir.ui.view,arch_db:pos_loyalty.loyalty_program_form_view |
||||
|
msgid "Rules" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.ui.view,arch_db:pos_loyalty.loyalty_program_form_view |
||||
|
msgid "" |
||||
|
"Rules define how loyalty points are earned for specific products or " |
||||
|
"categories" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_rule_category_id |
||||
|
msgid "Target Category" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_rule_product_id |
||||
|
msgid "Target Product" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,help:pos_loyalty.field_loyalty_reward_loyalty_program_id |
||||
|
msgid "The Loyalty Program this reward belongs to" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,help:pos_loyalty.field_loyalty_rule_loyalty_program_id |
||||
|
msgid "The Loyalty Program this rule belongs to" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,help:pos_loyalty.field_pos_order_loyalty_points |
||||
|
msgid "The amount of Loyalty points awarded to the customer with this order" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,help:pos_loyalty.field_loyalty_rule_category_id |
||||
|
msgid "The category affected by this rule" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,help:pos_loyalty.field_loyalty_rule_type |
||||
|
msgid "The concept this rule applies to" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,help:pos_loyalty.field_loyalty_reward_discount |
||||
|
msgid "The discount percentage" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,help:pos_loyalty.field_res_partner_loyalty_points |
||||
|
#: model:ir.model.fields,help:pos_loyalty.field_res_users_loyalty_points |
||||
|
msgid "The loyalty points the user won as part of a Loyalty Program" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,help:pos_loyalty.field_pos_config_loyalty_id |
||||
|
msgid "The loyalty program used by this Point of Sale" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,help:pos_loyalty.field_loyalty_rule_cumulative |
||||
|
msgid "" |
||||
|
"The points from this rule will be added to points won from other rules with " |
||||
|
"the same concept" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,help:pos_loyalty.field_loyalty_rule_product_id |
||||
|
msgid "The product affected by this rule" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,help:pos_loyalty.field_loyalty_reward_gift_product_id |
||||
|
msgid "The product given as a reward" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,help:pos_loyalty.field_loyalty_reward_discount_product_id |
||||
|
msgid "The product used to apply discounts" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#. openerp-web |
||||
|
#: code:addons/pos_loyalty/static/src/js/pos.js:380 |
||||
|
#, python-format |
||||
|
msgid "" |
||||
|
"There are no rewards available for this customer as part of the loyalty " |
||||
|
"program" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#. openerp-web |
||||
|
#: code:addons/pos_loyalty/static/src/xml/pos.xml:60 |
||||
|
#, python-format |
||||
|
msgid "Total Points" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_reward_type |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_rule_type |
||||
|
msgid "Type" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,help:pos_loyalty.field_loyalty_reward_type |
||||
|
msgid "Type of the reward" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.ui.view,arch_db:pos_loyalty.pos_config_view_form |
||||
|
msgid "abc" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model,name:pos_loyalty.model_loyalty_program |
||||
|
msgid "loyalty.program" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model,name:pos_loyalty.model_loyalty_reward |
||||
|
msgid "loyalty.reward" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model,name:pos_loyalty.model_loyalty_rule |
||||
|
msgid "loyalty.rule" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model,name:pos_loyalty.model_pos_config |
||||
|
msgid "pos.config" |
||||
|
msgstr "pos.config" |
@ -0,0 +1,497 @@ |
|||||
|
# Translation of Odoo Server. |
||||
|
# This file contains the translation of the following modules: |
||||
|
# * pos_loyalty |
||||
|
# |
||||
|
# Translators: |
||||
|
# Francesco Fresta <franco.fresta@gmail.com>, 2018 |
||||
|
msgid "" |
||||
|
msgstr "" |
||||
|
"Project-Id-Version: Odoo Server 10.0\n" |
||||
|
"Report-Msgid-Bugs-To: \n" |
||||
|
"POT-Creation-Date: 2018-03-01 02:01+0000\n" |
||||
|
"PO-Revision-Date: 2018-03-01 02:01+0000\n" |
||||
|
"Last-Translator: Francesco Fresta <franco.fresta@gmail.com>, 2018\n" |
||||
|
"Language-Team: Italian (https://www.transifex.com/oca/teams/23907/it/)\n" |
||||
|
"Language: it\n" |
||||
|
"MIME-Version: 1.0\n" |
||||
|
"Content-Type: text/plain; charset=UTF-8\n" |
||||
|
"Content-Transfer-Encoding: \n" |
||||
|
"Plural-Forms: nplurals=2; plural=(n != 1);\n" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,help:pos_loyalty.field_loyalty_program_pp_order |
||||
|
msgid "" |
||||
|
"Amount of loyalty points given to the customer for each point of sale order" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,help:pos_loyalty.field_loyalty_program_pp_product |
||||
|
msgid "Amount of loyalty points given to the customer per product sold" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,help:pos_loyalty.field_loyalty_program_pp_currency |
||||
|
msgid "Amount of loyalty points given to the customer per sold currency" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,help:pos_loyalty.field_loyalty_rule_pp_currency |
||||
|
msgid "Amount of points earned per currency" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,help:pos_loyalty.field_loyalty_rule_pp_product |
||||
|
msgid "Amount of points earned per product" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: selection:loyalty.rule,type:0 |
||||
|
msgid "Category" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.actions.act_window,help:pos_loyalty.loyalty_program_action |
||||
|
msgid "Click create to define a Loyalty Program." |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model,name:pos_loyalty.model_res_partner |
||||
|
msgid "Contact" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,help:pos_loyalty.field_loyalty_reward_point_cost |
||||
|
msgid "Cost of the reward per monetary unit discounted" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_program_create_uid |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_reward_create_uid |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_rule_create_uid |
||||
|
msgid "Created by" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_program_create_date |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_reward_create_date |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_rule_create_date |
||||
|
msgid "Created on" |
||||
|
msgstr "Creato il" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_rule_cumulative |
||||
|
msgid "Cumulative" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_reward_discount |
||||
|
#: selection:loyalty.reward,type:0 |
||||
|
msgid "Discount" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_reward_discount_product_id |
||||
|
msgid "Discount Product" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_reward_discount_max |
||||
|
msgid "Discount limit" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: code:addons/pos_loyalty/models/loyalty_reward.py:64 |
||||
|
#, python-format |
||||
|
msgid "Discount product field is mandatory for discount rewards" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_program_display_name |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_reward_display_name |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_rule_display_name |
||||
|
msgid "Display Name" |
||||
|
msgstr "Mostra il nome" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: selection:loyalty.reward,type:0 |
||||
|
msgid "Gift" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_reward_gift_product_id |
||||
|
msgid "Gift Product" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: code:addons/pos_loyalty/models/loyalty_reward.py:57 |
||||
|
#, python-format |
||||
|
msgid "Gift product field is mandatory for gift rewards" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_program_id |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_reward_id |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_rule_id |
||||
|
msgid "ID" |
||||
|
msgstr "ID" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_program___last_update |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_reward___last_update |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_rule___last_update |
||||
|
msgid "Last Modified on" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_program_write_uid |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_reward_write_uid |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_rule_write_uid |
||||
|
msgid "Last Updated by" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_program_write_date |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_reward_write_date |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_rule_write_date |
||||
|
msgid "Last Updated on" |
||||
|
msgstr "Ultimo aggiornamento il" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model,name:pos_loyalty.model_pos_order_line |
||||
|
#, fuzzy |
||||
|
msgid "Lines of Point of Sale Orders" |
||||
|
msgstr "Punto di riordino" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_pos_order_loyalty_points |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_res_partner_loyalty_points |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_res_users_loyalty_points |
||||
|
msgid "Loyalty Points" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_reward_loyalty_program_id |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_rule_loyalty_program_id |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_pos_config_loyalty_id |
||||
|
#: model:ir.ui.view,arch_db:pos_loyalty.loyalty_program_form_view |
||||
|
msgid "Loyalty Program" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.ui.view,arch_db:pos_loyalty.pos_config_view_form |
||||
|
msgid "Loyalty Program (OCA)" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_program_name |
||||
|
msgid "Loyalty Program Name" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.actions.act_window,name:pos_loyalty.loyalty_program_action |
||||
|
#: model:ir.ui.menu,name:pos_loyalty.loyalty_program_menu |
||||
|
#: model:ir.ui.view,arch_db:pos_loyalty.loyalty_program_tree_view |
||||
|
#: model:ir.ui.view,arch_db:pos_loyalty.partner_property_form_view |
||||
|
#: model:ir.ui.view,arch_db:pos_loyalty.pos_order_form_view |
||||
|
msgid "Loyalty Programs" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.actions.act_window,help:pos_loyalty.loyalty_program_action |
||||
|
msgid "" |
||||
|
"Loyalty Programs allow you customers to earn points\n" |
||||
|
" and rewards when purchasing from your shops." |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.ui.view,arch_db:pos_loyalty.loyalty_reward_form_view |
||||
|
msgid "Loyalty Reward" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.ui.view,arch_db:pos_loyalty.loyalty_rule_form_view |
||||
|
msgid "Loyalty Rule" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,help:pos_loyalty.field_loyalty_program_rounding |
||||
|
msgid "Loyalty point amounts will be rounded to multiples of this value" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.ui.view,arch_db:pos_loyalty.pos_config_view_form |
||||
|
msgid "Loyalty program that will be available in this PoS" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,help:pos_loyalty.field_loyalty_reward_discount_max |
||||
|
msgid "Maximum discounted amount allowed forthis discount reward" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_reward_minimum_points |
||||
|
msgid "Minimum Points" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,help:pos_loyalty.field_loyalty_reward_minimum_points |
||||
|
msgid "" |
||||
|
"Minimum amount of points the customer must have to qualify for this reward" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#. openerp-web |
||||
|
#: code:addons/pos_loyalty/static/src/js/pos.js:379 |
||||
|
#, python-format |
||||
|
msgid "No Rewards Available" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#. openerp-web |
||||
|
#: code:addons/pos_loyalty/static/src/js/pos.js:393 |
||||
|
#, python-format |
||||
|
msgid "Please select a reward" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_reward_point_cost |
||||
|
msgid "Point Cost" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_reward_point_product_id |
||||
|
msgid "Point Product" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model,name:pos_loyalty.model_pos_order |
||||
|
msgid "Point of Sale Orders" |
||||
|
msgstr "Punto di riordino" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: code:addons/pos_loyalty/models/loyalty_reward.py:72 |
||||
|
#, python-format |
||||
|
msgid "Point product field is mandatory for point resale rewards" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#. openerp-web |
||||
|
#: code:addons/pos_loyalty/static/src/xml/pos.xml:6 |
||||
|
#: code:addons/pos_loyalty/static/src/xml/pos.xml:71 |
||||
|
#: code:addons/pos_loyalty/static/src/xml/pos.xml:81 |
||||
|
#, python-format |
||||
|
msgid "Points" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_program_rounding |
||||
|
msgid "Points Rounding" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#. openerp-web |
||||
|
#: code:addons/pos_loyalty/static/src/xml/pos.xml:57 |
||||
|
#, python-format |
||||
|
msgid "Points Spent" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#. openerp-web |
||||
|
#: code:addons/pos_loyalty/static/src/xml/pos.xml:54 |
||||
|
#, python-format |
||||
|
msgid "Points Won" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_program_pp_currency |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_rule_pp_currency |
||||
|
msgid "Points per currency" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_program_pp_order |
||||
|
msgid "Points per order" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_program_pp_product |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_rule_pp_product |
||||
|
msgid "Points per product" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: selection:loyalty.rule,type:0 |
||||
|
msgid "Product" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,help:pos_loyalty.field_loyalty_reward_point_product_id |
||||
|
msgid "Product that represents a point that is sold by the customer" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: selection:loyalty.reward,type:0 |
||||
|
msgid "Resale" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_reward_name |
||||
|
msgid "Reward Name" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.ui.view,arch_db:pos_loyalty.loyalty_program_form_view |
||||
|
msgid "Reward the customer with gifts or discounts for loyalty points" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#. openerp-web |
||||
|
#: code:addons/pos_loyalty/static/src/xml/pos.xml:25 |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_program_reward_ids |
||||
|
#: model:ir.ui.view,arch_db:pos_loyalty.loyalty_program_form_view |
||||
|
#, python-format |
||||
|
msgid "Rewards" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_rule_name |
||||
|
msgid "Rule Name" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_program_rule_ids |
||||
|
#: model:ir.ui.view,arch_db:pos_loyalty.loyalty_program_form_view |
||||
|
msgid "Rules" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.ui.view,arch_db:pos_loyalty.loyalty_program_form_view |
||||
|
msgid "" |
||||
|
"Rules define how loyalty points are earned for specific products or " |
||||
|
"categories" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_rule_category_id |
||||
|
msgid "Target Category" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_rule_product_id |
||||
|
msgid "Target Product" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,help:pos_loyalty.field_loyalty_reward_loyalty_program_id |
||||
|
msgid "The Loyalty Program this reward belongs to" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,help:pos_loyalty.field_loyalty_rule_loyalty_program_id |
||||
|
msgid "The Loyalty Program this rule belongs to" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,help:pos_loyalty.field_pos_order_loyalty_points |
||||
|
msgid "The amount of Loyalty points awarded to the customer with this order" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,help:pos_loyalty.field_loyalty_rule_category_id |
||||
|
msgid "The category affected by this rule" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,help:pos_loyalty.field_loyalty_rule_type |
||||
|
msgid "The concept this rule applies to" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,help:pos_loyalty.field_loyalty_reward_discount |
||||
|
msgid "The discount percentage" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,help:pos_loyalty.field_res_partner_loyalty_points |
||||
|
#: model:ir.model.fields,help:pos_loyalty.field_res_users_loyalty_points |
||||
|
msgid "The loyalty points the user won as part of a Loyalty Program" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,help:pos_loyalty.field_pos_config_loyalty_id |
||||
|
msgid "The loyalty program used by this Point of Sale" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,help:pos_loyalty.field_loyalty_rule_cumulative |
||||
|
msgid "" |
||||
|
"The points from this rule will be added to points won from other rules with " |
||||
|
"the same concept" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,help:pos_loyalty.field_loyalty_rule_product_id |
||||
|
msgid "The product affected by this rule" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,help:pos_loyalty.field_loyalty_reward_gift_product_id |
||||
|
msgid "The product given as a reward" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,help:pos_loyalty.field_loyalty_reward_discount_product_id |
||||
|
msgid "The product used to apply discounts" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#. openerp-web |
||||
|
#: code:addons/pos_loyalty/static/src/js/pos.js:380 |
||||
|
#, python-format |
||||
|
msgid "" |
||||
|
"There are no rewards available for this customer as part of the loyalty " |
||||
|
"program" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#. openerp-web |
||||
|
#: code:addons/pos_loyalty/static/src/xml/pos.xml:60 |
||||
|
#, python-format |
||||
|
msgid "Total Points" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_reward_type |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_rule_type |
||||
|
msgid "Type" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,help:pos_loyalty.field_loyalty_reward_type |
||||
|
msgid "Type of the reward" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.ui.view,arch_db:pos_loyalty.pos_config_view_form |
||||
|
msgid "abc" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model,name:pos_loyalty.model_loyalty_program |
||||
|
msgid "loyalty.program" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model,name:pos_loyalty.model_loyalty_reward |
||||
|
msgid "loyalty.reward" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model,name:pos_loyalty.model_loyalty_rule |
||||
|
msgid "loyalty.rule" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model,name:pos_loyalty.model_pos_config |
||||
|
msgid "pos.config" |
||||
|
msgstr "pos.config" |
@ -0,0 +1,498 @@ |
|||||
|
# Translation of Odoo Server. |
||||
|
# This file contains the translation of the following modules: |
||||
|
# * pos_loyalty |
||||
|
# |
||||
|
# Translators: |
||||
|
# Peter Hageman <hageman.p@gmail.com>, 2017 |
||||
|
msgid "" |
||||
|
msgstr "" |
||||
|
"Project-Id-Version: Odoo Server 10.0\n" |
||||
|
"Report-Msgid-Bugs-To: \n" |
||||
|
"POT-Creation-Date: 2017-07-12 02:44+0000\n" |
||||
|
"PO-Revision-Date: 2017-07-12 02:44+0000\n" |
||||
|
"Last-Translator: Peter Hageman <hageman.p@gmail.com>, 2017\n" |
||||
|
"Language-Team: Dutch (Netherlands) (https://www.transifex.com/oca/" |
||||
|
"teams/23907/nl_NL/)\n" |
||||
|
"Language: nl_NL\n" |
||||
|
"MIME-Version: 1.0\n" |
||||
|
"Content-Type: text/plain; charset=UTF-8\n" |
||||
|
"Content-Transfer-Encoding: \n" |
||||
|
"Plural-Forms: nplurals=2; plural=(n != 1);\n" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,help:pos_loyalty.field_loyalty_program_pp_order |
||||
|
msgid "" |
||||
|
"Amount of loyalty points given to the customer for each point of sale order" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,help:pos_loyalty.field_loyalty_program_pp_product |
||||
|
msgid "Amount of loyalty points given to the customer per product sold" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,help:pos_loyalty.field_loyalty_program_pp_currency |
||||
|
msgid "Amount of loyalty points given to the customer per sold currency" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,help:pos_loyalty.field_loyalty_rule_pp_currency |
||||
|
msgid "Amount of points earned per currency" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,help:pos_loyalty.field_loyalty_rule_pp_product |
||||
|
msgid "Amount of points earned per product" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: selection:loyalty.rule,type:0 |
||||
|
msgid "Category" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.actions.act_window,help:pos_loyalty.loyalty_program_action |
||||
|
msgid "Click create to define a Loyalty Program." |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model,name:pos_loyalty.model_res_partner |
||||
|
msgid "Contact" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,help:pos_loyalty.field_loyalty_reward_point_cost |
||||
|
msgid "Cost of the reward per monetary unit discounted" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_program_create_uid |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_reward_create_uid |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_rule_create_uid |
||||
|
msgid "Created by" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_program_create_date |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_reward_create_date |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_rule_create_date |
||||
|
msgid "Created on" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_rule_cumulative |
||||
|
msgid "Cumulative" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_reward_discount |
||||
|
#: selection:loyalty.reward,type:0 |
||||
|
msgid "Discount" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_reward_discount_product_id |
||||
|
msgid "Discount Product" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_reward_discount_max |
||||
|
msgid "Discount limit" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: code:addons/pos_loyalty/models/loyalty_reward.py:64 |
||||
|
#, python-format |
||||
|
msgid "Discount product field is mandatory for discount rewards" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_program_display_name |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_reward_display_name |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_rule_display_name |
||||
|
msgid "Display Name" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: selection:loyalty.reward,type:0 |
||||
|
msgid "Gift" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_reward_gift_product_id |
||||
|
msgid "Gift Product" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: code:addons/pos_loyalty/models/loyalty_reward.py:57 |
||||
|
#, python-format |
||||
|
msgid "Gift product field is mandatory for gift rewards" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_program_id |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_reward_id |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_rule_id |
||||
|
msgid "ID" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_program___last_update |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_reward___last_update |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_rule___last_update |
||||
|
msgid "Last Modified on" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_program_write_uid |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_reward_write_uid |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_rule_write_uid |
||||
|
msgid "Last Updated by" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_program_write_date |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_reward_write_date |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_rule_write_date |
||||
|
msgid "Last Updated on" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model,name:pos_loyalty.model_pos_order_line |
||||
|
#, fuzzy |
||||
|
msgid "Lines of Point of Sale Orders" |
||||
|
msgstr "Kassaorders" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_pos_order_loyalty_points |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_res_partner_loyalty_points |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_res_users_loyalty_points |
||||
|
msgid "Loyalty Points" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_reward_loyalty_program_id |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_rule_loyalty_program_id |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_pos_config_loyalty_id |
||||
|
#: model:ir.ui.view,arch_db:pos_loyalty.loyalty_program_form_view |
||||
|
msgid "Loyalty Program" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.ui.view,arch_db:pos_loyalty.pos_config_view_form |
||||
|
msgid "Loyalty Program (OCA)" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_program_name |
||||
|
msgid "Loyalty Program Name" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.actions.act_window,name:pos_loyalty.loyalty_program_action |
||||
|
#: model:ir.ui.menu,name:pos_loyalty.loyalty_program_menu |
||||
|
#: model:ir.ui.view,arch_db:pos_loyalty.loyalty_program_tree_view |
||||
|
#: model:ir.ui.view,arch_db:pos_loyalty.partner_property_form_view |
||||
|
#: model:ir.ui.view,arch_db:pos_loyalty.pos_order_form_view |
||||
|
msgid "Loyalty Programs" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.actions.act_window,help:pos_loyalty.loyalty_program_action |
||||
|
msgid "" |
||||
|
"Loyalty Programs allow you customers to earn points\n" |
||||
|
" and rewards when purchasing from your shops." |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.ui.view,arch_db:pos_loyalty.loyalty_reward_form_view |
||||
|
msgid "Loyalty Reward" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.ui.view,arch_db:pos_loyalty.loyalty_rule_form_view |
||||
|
msgid "Loyalty Rule" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,help:pos_loyalty.field_loyalty_program_rounding |
||||
|
msgid "Loyalty point amounts will be rounded to multiples of this value" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.ui.view,arch_db:pos_loyalty.pos_config_view_form |
||||
|
msgid "Loyalty program that will be available in this PoS" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,help:pos_loyalty.field_loyalty_reward_discount_max |
||||
|
msgid "Maximum discounted amount allowed forthis discount reward" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_reward_minimum_points |
||||
|
msgid "Minimum Points" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,help:pos_loyalty.field_loyalty_reward_minimum_points |
||||
|
msgid "" |
||||
|
"Minimum amount of points the customer must have to qualify for this reward" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#. openerp-web |
||||
|
#: code:addons/pos_loyalty/static/src/js/pos.js:379 |
||||
|
#, python-format |
||||
|
msgid "No Rewards Available" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#. openerp-web |
||||
|
#: code:addons/pos_loyalty/static/src/js/pos.js:393 |
||||
|
#, python-format |
||||
|
msgid "Please select a reward" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_reward_point_cost |
||||
|
msgid "Point Cost" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_reward_point_product_id |
||||
|
msgid "Point Product" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model,name:pos_loyalty.model_pos_order |
||||
|
msgid "Point of Sale Orders" |
||||
|
msgstr "Kassaorders" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: code:addons/pos_loyalty/models/loyalty_reward.py:72 |
||||
|
#, python-format |
||||
|
msgid "Point product field is mandatory for point resale rewards" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#. openerp-web |
||||
|
#: code:addons/pos_loyalty/static/src/xml/pos.xml:6 |
||||
|
#: code:addons/pos_loyalty/static/src/xml/pos.xml:71 |
||||
|
#: code:addons/pos_loyalty/static/src/xml/pos.xml:81 |
||||
|
#, python-format |
||||
|
msgid "Points" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_program_rounding |
||||
|
msgid "Points Rounding" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#. openerp-web |
||||
|
#: code:addons/pos_loyalty/static/src/xml/pos.xml:57 |
||||
|
#, python-format |
||||
|
msgid "Points Spent" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#. openerp-web |
||||
|
#: code:addons/pos_loyalty/static/src/xml/pos.xml:54 |
||||
|
#, python-format |
||||
|
msgid "Points Won" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_program_pp_currency |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_rule_pp_currency |
||||
|
msgid "Points per currency" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_program_pp_order |
||||
|
msgid "Points per order" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_program_pp_product |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_rule_pp_product |
||||
|
msgid "Points per product" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: selection:loyalty.rule,type:0 |
||||
|
msgid "Product" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,help:pos_loyalty.field_loyalty_reward_point_product_id |
||||
|
msgid "Product that represents a point that is sold by the customer" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: selection:loyalty.reward,type:0 |
||||
|
msgid "Resale" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_reward_name |
||||
|
msgid "Reward Name" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.ui.view,arch_db:pos_loyalty.loyalty_program_form_view |
||||
|
msgid "Reward the customer with gifts or discounts for loyalty points" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#. openerp-web |
||||
|
#: code:addons/pos_loyalty/static/src/xml/pos.xml:25 |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_program_reward_ids |
||||
|
#: model:ir.ui.view,arch_db:pos_loyalty.loyalty_program_form_view |
||||
|
#, python-format |
||||
|
msgid "Rewards" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_rule_name |
||||
|
msgid "Rule Name" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_program_rule_ids |
||||
|
#: model:ir.ui.view,arch_db:pos_loyalty.loyalty_program_form_view |
||||
|
msgid "Rules" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.ui.view,arch_db:pos_loyalty.loyalty_program_form_view |
||||
|
msgid "" |
||||
|
"Rules define how loyalty points are earned for specific products or " |
||||
|
"categories" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_rule_category_id |
||||
|
msgid "Target Category" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_rule_product_id |
||||
|
msgid "Target Product" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,help:pos_loyalty.field_loyalty_reward_loyalty_program_id |
||||
|
msgid "The Loyalty Program this reward belongs to" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,help:pos_loyalty.field_loyalty_rule_loyalty_program_id |
||||
|
msgid "The Loyalty Program this rule belongs to" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,help:pos_loyalty.field_pos_order_loyalty_points |
||||
|
msgid "The amount of Loyalty points awarded to the customer with this order" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,help:pos_loyalty.field_loyalty_rule_category_id |
||||
|
msgid "The category affected by this rule" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,help:pos_loyalty.field_loyalty_rule_type |
||||
|
msgid "The concept this rule applies to" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,help:pos_loyalty.field_loyalty_reward_discount |
||||
|
msgid "The discount percentage" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,help:pos_loyalty.field_res_partner_loyalty_points |
||||
|
#: model:ir.model.fields,help:pos_loyalty.field_res_users_loyalty_points |
||||
|
msgid "The loyalty points the user won as part of a Loyalty Program" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,help:pos_loyalty.field_pos_config_loyalty_id |
||||
|
msgid "The loyalty program used by this Point of Sale" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,help:pos_loyalty.field_loyalty_rule_cumulative |
||||
|
msgid "" |
||||
|
"The points from this rule will be added to points won from other rules with " |
||||
|
"the same concept" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,help:pos_loyalty.field_loyalty_rule_product_id |
||||
|
msgid "The product affected by this rule" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,help:pos_loyalty.field_loyalty_reward_gift_product_id |
||||
|
msgid "The product given as a reward" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,help:pos_loyalty.field_loyalty_reward_discount_product_id |
||||
|
msgid "The product used to apply discounts" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#. openerp-web |
||||
|
#: code:addons/pos_loyalty/static/src/js/pos.js:380 |
||||
|
#, python-format |
||||
|
msgid "" |
||||
|
"There are no rewards available for this customer as part of the loyalty " |
||||
|
"program" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#. openerp-web |
||||
|
#: code:addons/pos_loyalty/static/src/xml/pos.xml:60 |
||||
|
#, python-format |
||||
|
msgid "Total Points" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_reward_type |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_rule_type |
||||
|
msgid "Type" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,help:pos_loyalty.field_loyalty_reward_type |
||||
|
msgid "Type of the reward" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.ui.view,arch_db:pos_loyalty.pos_config_view_form |
||||
|
msgid "abc" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model,name:pos_loyalty.model_loyalty_program |
||||
|
msgid "loyalty.program" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model,name:pos_loyalty.model_loyalty_reward |
||||
|
msgid "loyalty.reward" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model,name:pos_loyalty.model_loyalty_rule |
||||
|
msgid "loyalty.rule" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model,name:pos_loyalty.model_pos_config |
||||
|
msgid "pos.config" |
||||
|
msgstr "pos.config" |
@ -0,0 +1,483 @@ |
|||||
|
# Translation of Odoo Server. |
||||
|
# This file contains the translation of the following modules: |
||||
|
# * pos_loyalty |
||||
|
# |
||||
|
msgid "" |
||||
|
msgstr "" |
||||
|
"Project-Id-Version: Odoo Server 11.0\n" |
||||
|
"Report-Msgid-Bugs-To: \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: pos_loyalty |
||||
|
#: model:ir.model.fields,help:pos_loyalty.field_loyalty_program_pp_order |
||||
|
msgid "Amount of loyalty points given to the customer for each point of sale order" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,help:pos_loyalty.field_loyalty_program_pp_product |
||||
|
msgid "Amount of loyalty points given to the customer per product sold" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,help:pos_loyalty.field_loyalty_program_pp_currency |
||||
|
msgid "Amount of loyalty points given to the customer per sold currency" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,help:pos_loyalty.field_loyalty_rule_pp_currency |
||||
|
msgid "Amount of points earned per currency" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,help:pos_loyalty.field_loyalty_rule_pp_product |
||||
|
msgid "Amount of points earned per product" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: selection:loyalty.rule,type:0 |
||||
|
msgid "Category" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.actions.act_window,help:pos_loyalty.loyalty_program_action |
||||
|
msgid "Click create to define a Loyalty Program." |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model,name:pos_loyalty.model_res_partner |
||||
|
msgid "Contact" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,help:pos_loyalty.field_loyalty_reward_point_cost |
||||
|
msgid "Cost of the reward per monetary unit discounted" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_program_create_uid |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_reward_create_uid |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_rule_create_uid |
||||
|
msgid "Created by" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_program_create_date |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_reward_create_date |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_rule_create_date |
||||
|
msgid "Created on" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_rule_cumulative |
||||
|
msgid "Cumulative" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_reward_discount |
||||
|
#: selection:loyalty.reward,type:0 |
||||
|
msgid "Discount" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_reward_discount_product_id |
||||
|
msgid "Discount Product" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_reward_discount_max |
||||
|
msgid "Discount limit" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: code:addons/pos_loyalty/models/loyalty_reward.py:64 |
||||
|
#, python-format |
||||
|
msgid "Discount product field is mandatory for discount rewards" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_program_display_name |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_reward_display_name |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_rule_display_name |
||||
|
msgid "Display Name" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: selection:loyalty.reward,type:0 |
||||
|
msgid "Gift" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_reward_gift_product_id |
||||
|
msgid "Gift Product" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: code:addons/pos_loyalty/models/loyalty_reward.py:57 |
||||
|
#, python-format |
||||
|
msgid "Gift product field is mandatory for gift rewards" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_program_id |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_reward_id |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_rule_id |
||||
|
msgid "ID" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_program___last_update |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_reward___last_update |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_rule___last_update |
||||
|
msgid "Last Modified on" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_program_write_uid |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_reward_write_uid |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_rule_write_uid |
||||
|
msgid "Last Updated by" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_program_write_date |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_reward_write_date |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_rule_write_date |
||||
|
msgid "Last Updated on" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model,name:pos_loyalty.model_pos_order_line |
||||
|
msgid "Lines of Point of Sale Orders" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_pos_order_loyalty_points |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_res_partner_loyalty_points |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_res_users_loyalty_points |
||||
|
msgid "Loyalty Points" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_reward_loyalty_program_id |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_rule_loyalty_program_id |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_pos_config_loyalty_id |
||||
|
#: model:ir.ui.view,arch_db:pos_loyalty.loyalty_program_form_view |
||||
|
msgid "Loyalty Program" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.ui.view,arch_db:pos_loyalty.pos_config_view_form |
||||
|
msgid "Loyalty Program (OCA)" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_program_name |
||||
|
msgid "Loyalty Program Name" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.actions.act_window,name:pos_loyalty.loyalty_program_action |
||||
|
#: model:ir.ui.menu,name:pos_loyalty.loyalty_program_menu |
||||
|
#: model:ir.ui.view,arch_db:pos_loyalty.loyalty_program_tree_view |
||||
|
#: model:ir.ui.view,arch_db:pos_loyalty.partner_property_form_view |
||||
|
#: model:ir.ui.view,arch_db:pos_loyalty.pos_order_form_view |
||||
|
msgid "Loyalty Programs" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.actions.act_window,help:pos_loyalty.loyalty_program_action |
||||
|
msgid "Loyalty Programs allow you customers to earn points\n" |
||||
|
" and rewards when purchasing from your shops." |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.ui.view,arch_db:pos_loyalty.loyalty_reward_form_view |
||||
|
msgid "Loyalty Reward" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.ui.view,arch_db:pos_loyalty.loyalty_rule_form_view |
||||
|
msgid "Loyalty Rule" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,help:pos_loyalty.field_loyalty_program_rounding |
||||
|
msgid "Loyalty point amounts will be rounded to multiples of this value" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.ui.view,arch_db:pos_loyalty.pos_config_view_form |
||||
|
msgid "Loyalty program that will be available in this PoS" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,help:pos_loyalty.field_loyalty_reward_discount_max |
||||
|
msgid "Maximum discounted amount allowed forthis discount reward" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_reward_minimum_points |
||||
|
msgid "Minimum Points" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,help:pos_loyalty.field_loyalty_reward_minimum_points |
||||
|
msgid "Minimum amount of points the customer must have to qualify for this reward" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#. openerp-web |
||||
|
#: code:addons/pos_loyalty/static/src/js/pos.js:379 |
||||
|
#, python-format |
||||
|
msgid "No Rewards Available" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#. openerp-web |
||||
|
#: code:addons/pos_loyalty/static/src/js/pos.js:393 |
||||
|
#, python-format |
||||
|
msgid "Please select a reward" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_reward_point_cost |
||||
|
msgid "Point Cost" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_reward_point_product_id |
||||
|
msgid "Point Product" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model,name:pos_loyalty.model_pos_order |
||||
|
msgid "Point of Sale Orders" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: code:addons/pos_loyalty/models/loyalty_reward.py:72 |
||||
|
#, python-format |
||||
|
msgid "Point product field is mandatory for point resale rewards" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#. openerp-web |
||||
|
#: code:addons/pos_loyalty/static/src/xml/pos.xml:6 |
||||
|
#: code:addons/pos_loyalty/static/src/xml/pos.xml:71 |
||||
|
#: code:addons/pos_loyalty/static/src/xml/pos.xml:81 |
||||
|
#, python-format |
||||
|
msgid "Points" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_program_rounding |
||||
|
msgid "Points Rounding" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#. openerp-web |
||||
|
#: code:addons/pos_loyalty/static/src/xml/pos.xml:57 |
||||
|
#, python-format |
||||
|
msgid "Points Spent" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#. openerp-web |
||||
|
#: code:addons/pos_loyalty/static/src/xml/pos.xml:54 |
||||
|
#, python-format |
||||
|
msgid "Points Won" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_program_pp_currency |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_rule_pp_currency |
||||
|
msgid "Points per currency" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_program_pp_order |
||||
|
msgid "Points per order" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_program_pp_product |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_rule_pp_product |
||||
|
msgid "Points per product" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: selection:loyalty.rule,type:0 |
||||
|
msgid "Product" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,help:pos_loyalty.field_loyalty_reward_point_product_id |
||||
|
msgid "Product that represents a point that is sold by the customer" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: selection:loyalty.reward,type:0 |
||||
|
msgid "Resale" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_reward_name |
||||
|
msgid "Reward Name" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.ui.view,arch_db:pos_loyalty.loyalty_program_form_view |
||||
|
msgid "Reward the customer with gifts or discounts for loyalty points" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#. openerp-web |
||||
|
#: code:addons/pos_loyalty/static/src/xml/pos.xml:25 |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_program_reward_ids |
||||
|
#: model:ir.ui.view,arch_db:pos_loyalty.loyalty_program_form_view |
||||
|
#, python-format |
||||
|
msgid "Rewards" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_rule_name |
||||
|
msgid "Rule Name" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_program_rule_ids |
||||
|
#: model:ir.ui.view,arch_db:pos_loyalty.loyalty_program_form_view |
||||
|
msgid "Rules" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.ui.view,arch_db:pos_loyalty.loyalty_program_form_view |
||||
|
msgid "Rules define how loyalty points are earned for specific products or categories" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_rule_category_id |
||||
|
msgid "Target Category" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_rule_product_id |
||||
|
msgid "Target Product" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,help:pos_loyalty.field_loyalty_reward_loyalty_program_id |
||||
|
msgid "The Loyalty Program this reward belongs to" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,help:pos_loyalty.field_loyalty_rule_loyalty_program_id |
||||
|
msgid "The Loyalty Program this rule belongs to" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,help:pos_loyalty.field_pos_order_loyalty_points |
||||
|
msgid "The amount of Loyalty points awarded to the customer with this order" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,help:pos_loyalty.field_loyalty_rule_category_id |
||||
|
msgid "The category affected by this rule" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,help:pos_loyalty.field_loyalty_rule_type |
||||
|
msgid "The concept this rule applies to" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,help:pos_loyalty.field_loyalty_reward_discount |
||||
|
msgid "The discount percentage" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,help:pos_loyalty.field_res_partner_loyalty_points |
||||
|
#: model:ir.model.fields,help:pos_loyalty.field_res_users_loyalty_points |
||||
|
msgid "The loyalty points the user won as part of a Loyalty Program" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,help:pos_loyalty.field_pos_config_loyalty_id |
||||
|
msgid "The loyalty program used by this Point of Sale" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,help:pos_loyalty.field_loyalty_rule_cumulative |
||||
|
msgid "The points from this rule will be added to points won from other rules with the same concept" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,help:pos_loyalty.field_loyalty_rule_product_id |
||||
|
msgid "The product affected by this rule" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,help:pos_loyalty.field_loyalty_reward_gift_product_id |
||||
|
msgid "The product given as a reward" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,help:pos_loyalty.field_loyalty_reward_discount_product_id |
||||
|
msgid "The product used to apply discounts" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#. openerp-web |
||||
|
#: code:addons/pos_loyalty/static/src/js/pos.js:380 |
||||
|
#, python-format |
||||
|
msgid "There are no rewards available for this customer as part of the loyalty program" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#. openerp-web |
||||
|
#: code:addons/pos_loyalty/static/src/xml/pos.xml:60 |
||||
|
#, python-format |
||||
|
msgid "Total Points" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_reward_type |
||||
|
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_rule_type |
||||
|
msgid "Type" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model.fields,help:pos_loyalty.field_loyalty_reward_type |
||||
|
msgid "Type of the reward" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.ui.view,arch_db:pos_loyalty.pos_config_view_form |
||||
|
msgid "abc" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model,name:pos_loyalty.model_loyalty_program |
||||
|
msgid "loyalty.program" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model,name:pos_loyalty.model_loyalty_reward |
||||
|
msgid "loyalty.reward" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model,name:pos_loyalty.model_loyalty_rule |
||||
|
msgid "loyalty.rule" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_loyalty |
||||
|
#: model:ir.model,name:pos_loyalty.model_pos_config |
||||
|
msgid "pos.config" |
||||
|
msgstr "" |
||||
|
|
@ -0,0 +1,9 @@ |
|||||
|
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). |
||||
|
|
||||
|
from . import loyalty_program |
||||
|
from . import loyalty_reward |
||||
|
from . import loyalty_rule |
||||
|
from . import pos_config |
||||
|
from . import pos_order |
||||
|
from . import pos_order_line |
||||
|
from . import res_partner |
@ -0,0 +1,30 @@ |
|||||
|
# Copyright 2004-2010 OpenERP SA |
||||
|
# Copyright 2017 RGB Consulting S.L. (https://www.rgbconsulting.com) |
||||
|
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). |
||||
|
|
||||
|
from odoo import fields, models |
||||
|
|
||||
|
|
||||
|
class LoyaltyProgram(models.Model): |
||||
|
_name = 'loyalty.program' |
||||
|
|
||||
|
name = fields.Char(string='Loyalty Program Name', size=32, index=True, |
||||
|
required=True) |
||||
|
pp_currency = fields.Float(string='Points per currency', |
||||
|
help='Amount of loyalty points given to the ' |
||||
|
'customer per sold currency') |
||||
|
pp_product = fields.Float(string='Points per product', |
||||
|
help='Amount of loyalty points given to the ' |
||||
|
'customer per product sold') |
||||
|
pp_order = fields.Float(string='Points per order', |
||||
|
help='Amount of loyalty points given to the ' |
||||
|
'customer for each point of sale order') |
||||
|
rounding = fields.Float(string='Points Rounding', default=1, |
||||
|
help='Loyalty point amounts will be rounded to ' |
||||
|
'multiples of this value') |
||||
|
rule_ids = fields.One2many(comodel_name='loyalty.rule', |
||||
|
inverse_name='loyalty_program_id', |
||||
|
string='Rules') |
||||
|
reward_ids = fields.One2many(comodel_name='loyalty.reward', |
||||
|
inverse_name='loyalty_program_id', |
||||
|
string='Rewards') |
@ -0,0 +1,73 @@ |
|||||
|
# Copyright 2004-2010 OpenERP SA |
||||
|
# Copyright 2017 RGB Consulting S.L. (https://www.rgbconsulting.com) |
||||
|
# Copyright 2018 Lambda IS DOOEL <https://www.lambda-is.com> |
||||
|
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). |
||||
|
|
||||
|
from odoo import fields, models, api, _ |
||||
|
from odoo.exceptions import ValidationError |
||||
|
|
||||
|
|
||||
|
class LoyaltyReward(models.Model): |
||||
|
_name = 'loyalty.reward' |
||||
|
|
||||
|
name = fields.Char(string='Reward Name', size=32, index=True, |
||||
|
required=True) |
||||
|
type = fields.Selection(selection=[('gift', 'Gift'), |
||||
|
('discount', 'Discount'), |
||||
|
('resale', 'Resale')], |
||||
|
string='Type', required=True, |
||||
|
help='Type of the reward') |
||||
|
minimum_points = fields.Float(string='Minimum Points', |
||||
|
help='Minimum amount of points the customer' |
||||
|
' must have to qualify for this reward') |
||||
|
point_cost = fields.Float(string='Point Cost', |
||||
|
help='Cost of the reward per monetary unit ' |
||||
|
'discounted') |
||||
|
discount = fields.Float(help='The discount percentage') |
||||
|
discount_max = fields.Float(string='Discount limit', |
||||
|
help='Maximum discounted amount allowed for' |
||||
|
'this discount reward') |
||||
|
loyalty_program_id = fields.Many2one(comodel_name='loyalty.program', |
||||
|
string='Loyalty Program', |
||||
|
help='The Loyalty Program this reward' |
||||
|
' belongs to') |
||||
|
gift_product_id = fields.Many2one(comodel_name='product.product', |
||||
|
domain=[('available_in_pos', '=', True)], |
||||
|
string='Gift Product', |
||||
|
help='The product given as a reward') |
||||
|
discount_product_id = fields.Many2one(comodel_name='product.product', |
||||
|
domain=[ |
||||
|
('available_in_pos', '=', True)], |
||||
|
string='Discount Product', |
||||
|
help='The product used to apply ' |
||||
|
'discounts') |
||||
|
point_product_id = fields.Many2one(comodel_name='product.product', |
||||
|
domain=[ |
||||
|
('available_in_pos', '=', True)], |
||||
|
string='Point Product', |
||||
|
help='Product that represents a point ' |
||||
|
'that is sold by the customer') |
||||
|
|
||||
|
@api.multi |
||||
|
@api.constrains('type', 'gift_product_id') |
||||
|
def _check_gift_product(self): |
||||
|
for reward in self: |
||||
|
if reward.type == 'gift' and not reward.gift_product_id: |
||||
|
raise ValidationError( |
||||
|
_('Gift product field is mandatory for gift rewards')) |
||||
|
|
||||
|
@api.multi |
||||
|
@api.constrains('type', 'discount_product_id') |
||||
|
def _check_discount_product(self): |
||||
|
for reward in self: |
||||
|
if reward.type == 'discount' and not reward.discount_product_id: |
||||
|
raise ValidationError(_('Discount product field is ' |
||||
|
'mandatory for discount rewards')) |
||||
|
|
||||
|
@api.multi |
||||
|
@api.constrains('type', 'point_product_id') |
||||
|
def _check_point_product(self): |
||||
|
for reward in self: |
||||
|
if reward.type == 'resale' and not reward.point_product_id: |
||||
|
raise ValidationError(_('Point product field is ' |
||||
|
'mandatory for point resale rewards')) |
@ -0,0 +1,34 @@ |
|||||
|
# Copyright 2004-2010 OpenERP SA |
||||
|
# Copyright 2017 RGB Consulting S.L. (https://www.rgbconsulting.com) |
||||
|
# Copyright 2018 Lambda IS DOOEL <https://www.lambda-is.com> |
||||
|
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). |
||||
|
|
||||
|
from odoo import fields, models |
||||
|
|
||||
|
|
||||
|
class LoyaltyRule(models.Model): |
||||
|
_name = 'loyalty.rule' |
||||
|
|
||||
|
name = fields.Char(string='Rule Name', size=32, index=True, required=True) |
||||
|
type = fields.Selection(selection=[('product', 'Product'), |
||||
|
('category', 'Category')], |
||||
|
string='Type', required=True, default='product', |
||||
|
help='The concept this rule applies to') |
||||
|
cumulative = fields.Boolean(help='The points from this rule will be added ' |
||||
|
'to points won from other rules with ' |
||||
|
'the same concept') |
||||
|
pp_product = fields.Float(string='Points per product', |
||||
|
help='Amount of points earned per product') |
||||
|
pp_currency = fields.Float(string='Points per currency', |
||||
|
help='Amount of points earned per currency') |
||||
|
loyalty_program_id = fields.Many2one(comodel_name='loyalty.program', |
||||
|
string='Loyalty Program', |
||||
|
help='The Loyalty Program this rule ' |
||||
|
'belongs to') |
||||
|
product_id = fields.Many2one(comodel_name='product.product', |
||||
|
domain=[('available_in_pos', '=', True)], |
||||
|
string='Target Product', |
||||
|
help='The product affected by this rule') |
||||
|
category_id = fields.Many2one(comodel_name='pos.category', |
||||
|
string='Target Category', |
||||
|
help='The category affected by this rule') |
@ -0,0 +1,14 @@ |
|||||
|
# Copyright 2004-2010 OpenERP SA |
||||
|
# Copyright 2017 RGB Consulting S.L. (https://www.rgbconsulting.com) |
||||
|
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). |
||||
|
|
||||
|
from odoo import fields, models |
||||
|
|
||||
|
|
||||
|
class PosConfig(models.Model): |
||||
|
_inherit = 'pos.config' |
||||
|
|
||||
|
loyalty_id = fields.Many2one(comodel_name='loyalty.program', |
||||
|
string='Loyalty Program', |
||||
|
help='The loyalty program used by this ' |
||||
|
'Point of Sale') |
@ -0,0 +1,30 @@ |
|||||
|
# Copyright 2004-2010 OpenERP SA |
||||
|
# Copyright 2017 RGB Consulting S.L. (https://www.rgbconsulting.com) |
||||
|
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). |
||||
|
|
||||
|
from odoo import fields, models, api |
||||
|
|
||||
|
|
||||
|
class PosOrder(models.Model): |
||||
|
_inherit = 'pos.order' |
||||
|
|
||||
|
loyalty_points = fields.Float(string='Loyalty Points', |
||||
|
help='The amount of Loyalty points awarded ' |
||||
|
'to the customer with this order') |
||||
|
|
||||
|
@api.model |
||||
|
def _order_fields(self, ui_order): |
||||
|
res = super(PosOrder, self)._order_fields(ui_order) |
||||
|
res['loyalty_points'] = ui_order.get('loyalty_points', 0) |
||||
|
return res |
||||
|
|
||||
|
@api.model |
||||
|
def create_from_ui(self, orders): |
||||
|
res = super(PosOrder, self).create_from_ui(orders) |
||||
|
for order in orders: |
||||
|
order_partner = order['data']['partner_id'] |
||||
|
order_points = order['data'].get('loyalty_points', 0) |
||||
|
if order_points != 0 and order_partner: |
||||
|
partner = self.env['res.partner'].browse(order_partner) |
||||
|
partner.loyalty_points += order_points |
||||
|
return res |
@ -0,0 +1,20 @@ |
|||||
|
# Copyright 2018 Lambda IS DOOEL <https://www.lambda-is.com> |
||||
|
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). |
||||
|
|
||||
|
from odoo import api, models |
||||
|
|
||||
|
|
||||
|
class PosOrderLine(models.Model): |
||||
|
_inherit = 'pos.order.line' |
||||
|
|
||||
|
@api.model |
||||
|
def _order_line_fields(self, line, session_id=None): |
||||
|
line = super(PosOrderLine, self)._order_line_fields( |
||||
|
line, session_id=session_id) |
||||
|
if line and 'reward_id' in line[2]: |
||||
|
# Delete the key since field doesn't exist |
||||
|
# and raises a warning in the logs. |
||||
|
# TODO: add field and remove this if data will be |
||||
|
# used on server, example in report / widget. |
||||
|
del line[2]['reward_id'] |
||||
|
return line |
@ -0,0 +1,13 @@ |
|||||
|
# Copyright 2004-2010 OpenERP SA |
||||
|
# Copyright 2017 RGB Consulting S.L. (https://www.rgbconsulting.com) |
||||
|
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). |
||||
|
|
||||
|
from odoo import fields, models |
||||
|
|
||||
|
|
||||
|
class ResPartner(models.Model): |
||||
|
_inherit = 'res.partner' |
||||
|
|
||||
|
loyalty_points = fields.Float(string='Loyalty Points', |
||||
|
help='The loyalty points the user won as ' |
||||
|
'part of a Loyalty Program') |
@ -0,0 +1,4 @@ |
|||||
|
To use this module, you need to: |
||||
|
|
||||
|
* Go to *Point of Sale > Configuration > Loyalty Programs* and define a new loyalty program with specific rules and rewards. |
||||
|
* Assign the loyalty program to the desired Point of Sale. |
@ -0,0 +1,3 @@ |
|||||
|
* RGB Consulting SL (http://www.rgbconsulting.com) |
||||
|
* Forward-port from Odoo SA saas-6 branch |
||||
|
* Kiril Vangelovski <kiril@lambda-is.com> |
@ -0,0 +1,6 @@ |
|||||
|
This module allows you to define a loyalty program in the point of sale, |
||||
|
where the customers earn loyalty points and get rewards. |
||||
|
|
||||
|
This module is a forward-port to v12 of the pos_loyalty module from Odoo's |
||||
|
saas-6 branch. |
||||
|
The functionality was moved to the Enterprise edition in later versions. |
@ -0,0 +1,11 @@ |
|||||
|
The Loyalty Program defines rules for acquiring points and rewards on which they can be spent. |
||||
|
|
||||
|
Rules can be defined globally for all products (fields on loyalty.program) and / or rules that are applied only on specific product or PoS category (loyalty.rule records) on a *points per product sold* or *points per currency spent* basis. The specific rules (loyalty.rule) can be defined as cumulative, which means that they will be aggregated with other matching rules (loyalty.rule records and loyalty.program fields). In the case of non-cumulative rules only the points from that one matching rule are used. Additionally, *fixed points per order* can be added which are applied regardless of whether or not cumulative or non-cumulative rules were applied also. |
||||
|
|
||||
|
Rewards can be of three types: |
||||
|
|
||||
|
* *Gift* - give a single unit of product for free |
||||
|
* *Discount* - give a discount to the whole order. It should be added at the end of the order so that the correct total price is used. |
||||
|
* *Resale* - allow for customer to sell back his earned points. These are calculated by setting the price on the Resale product (*resale_product.list_price* * *customer.loyalty_points*) |
||||
|
|
||||
|
All rewards can define how many points they cost (point_cost) and how many are needed so that the customer can become eligable for the reward (minimum_points). for Gift and Discount rewards minimum_points are considered only if they are greater then the point_cost for that reward (minimum_points > point_cost). For Resale products only minimum_points can be used. |
@ -0,0 +1,7 @@ |
|||||
|
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink |
||||
|
access_loyalty_program,loyalty.program.user,model_loyalty_program,point_of_sale.group_pos_user,1,0,0,0 |
||||
|
access_loyalty_program_manager,loyalty.program.manager,model_loyalty_program,point_of_sale.group_pos_manager,1,1,1,1 |
||||
|
access_loyalty_rule,loyalty.rule.user,model_loyalty_rule,point_of_sale.group_pos_user,1,0,0,0 |
||||
|
access_loyalty_rule_manager,loyalty.rule.manager,model_loyalty_rule,point_of_sale.group_pos_manager,1,1,1,1 |
||||
|
access_loyalty_reward,loyalty.reward.user,model_loyalty_reward,point_of_sale.group_pos_user,1,0,0,0 |
||||
|
access_loyalty_reward_manager,loyalty.reward.manager,model_loyalty_reward,point_of_sale.group_pos_manager,1,1,1,1 |
After Width: 128 | Height: 128 | Size: 9.2 KiB |
@ -0,0 +1,449 @@ |
|||||
|
<?xml version="1.0" encoding="utf-8" ?> |
||||
|
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> |
||||
|
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> |
||||
|
<head> |
||||
|
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> |
||||
|
<meta name="generator" content="Docutils 0.14: http://docutils.sourceforge.net/" /> |
||||
|
<title>Loyalty Program</title> |
||||
|
<style type="text/css"> |
||||
|
|
||||
|
/* |
||||
|
:Author: David Goodger (goodger@python.org) |
||||
|
:Id: $Id: html4css1.css 7952 2016-07-26 18:15:59Z milde $ |
||||
|
:Copyright: This stylesheet has been placed in the public domain. |
||||
|
|
||||
|
Default cascading style sheet for the HTML output of Docutils. |
||||
|
|
||||
|
See http://docutils.sf.net/docs/howto/html-stylesheets.html for how to |
||||
|
customize this style sheet. |
||||
|
*/ |
||||
|
|
||||
|
/* used to remove borders from tables and images */ |
||||
|
.borderless, table.borderless td, table.borderless th { |
||||
|
border: 0 } |
||||
|
|
||||
|
table.borderless td, table.borderless th { |
||||
|
/* Override padding for "table.docutils td" with "! important". |
||||
|
The right padding separates the table cells. */ |
||||
|
padding: 0 0.5em 0 0 ! important } |
||||
|
|
||||
|
.first { |
||||
|
/* Override more specific margin styles with "! important". */ |
||||
|
margin-top: 0 ! important } |
||||
|
|
||||
|
.last, .with-subtitle { |
||||
|
margin-bottom: 0 ! important } |
||||
|
|
||||
|
.hidden { |
||||
|
display: none } |
||||
|
|
||||
|
.subscript { |
||||
|
vertical-align: sub; |
||||
|
font-size: smaller } |
||||
|
|
||||
|
.superscript { |
||||
|
vertical-align: super; |
||||
|
font-size: smaller } |
||||
|
|
||||
|
a.toc-backref { |
||||
|
text-decoration: none ; |
||||
|
color: black } |
||||
|
|
||||
|
blockquote.epigraph { |
||||
|
margin: 2em 5em ; } |
||||
|
|
||||
|
dl.docutils dd { |
||||
|
margin-bottom: 0.5em } |
||||
|
|
||||
|
object[type="image/svg+xml"], object[type="application/x-shockwave-flash"] { |
||||
|
overflow: hidden; |
||||
|
} |
||||
|
|
||||
|
/* Uncomment (and remove this text!) to get bold-faced definition list terms |
||||
|
dl.docutils dt { |
||||
|
font-weight: bold } |
||||
|
*/ |
||||
|
|
||||
|
div.abstract { |
||||
|
margin: 2em 5em } |
||||
|
|
||||
|
div.abstract p.topic-title { |
||||
|
font-weight: bold ; |
||||
|
text-align: center } |
||||
|
|
||||
|
div.admonition, div.attention, div.caution, div.danger, div.error, |
||||
|
div.hint, div.important, div.note, div.tip, div.warning { |
||||
|
margin: 2em ; |
||||
|
border: medium outset ; |
||||
|
padding: 1em } |
||||
|
|
||||
|
div.admonition p.admonition-title, div.hint p.admonition-title, |
||||
|
div.important p.admonition-title, div.note p.admonition-title, |
||||
|
div.tip p.admonition-title { |
||||
|
font-weight: bold ; |
||||
|
font-family: sans-serif } |
||||
|
|
||||
|
div.attention p.admonition-title, div.caution p.admonition-title, |
||||
|
div.danger p.admonition-title, div.error p.admonition-title, |
||||
|
div.warning p.admonition-title, .code .error { |
||||
|
color: red ; |
||||
|
font-weight: bold ; |
||||
|
font-family: sans-serif } |
||||
|
|
||||
|
/* Uncomment (and remove this text!) to get reduced vertical space in |
||||
|
compound paragraphs. |
||||
|
div.compound .compound-first, div.compound .compound-middle { |
||||
|
margin-bottom: 0.5em } |
||||
|
|
||||
|
div.compound .compound-last, div.compound .compound-middle { |
||||
|
margin-top: 0.5em } |
||||
|
*/ |
||||
|
|
||||
|
div.dedication { |
||||
|
margin: 2em 5em ; |
||||
|
text-align: center ; |
||||
|
font-style: italic } |
||||
|
|
||||
|
div.dedication p.topic-title { |
||||
|
font-weight: bold ; |
||||
|
font-style: normal } |
||||
|
|
||||
|
div.figure { |
||||
|
margin-left: 2em ; |
||||
|
margin-right: 2em } |
||||
|
|
||||
|
div.footer, div.header { |
||||
|
clear: both; |
||||
|
font-size: smaller } |
||||
|
|
||||
|
div.line-block { |
||||
|
display: block ; |
||||
|
margin-top: 1em ; |
||||
|
margin-bottom: 1em } |
||||
|
|
||||
|
div.line-block div.line-block { |
||||
|
margin-top: 0 ; |
||||
|
margin-bottom: 0 ; |
||||
|
margin-left: 1.5em } |
||||
|
|
||||
|
div.sidebar { |
||||
|
margin: 0 0 0.5em 1em ; |
||||
|
border: medium outset ; |
||||
|
padding: 1em ; |
||||
|
background-color: #ffffee ; |
||||
|
width: 40% ; |
||||
|
float: right ; |
||||
|
clear: right } |
||||
|
|
||||
|
div.sidebar p.rubric { |
||||
|
font-family: sans-serif ; |
||||
|
font-size: medium } |
||||
|
|
||||
|
div.system-messages { |
||||
|
margin: 5em } |
||||
|
|
||||
|
div.system-messages h1 { |
||||
|
color: red } |
||||
|
|
||||
|
div.system-message { |
||||
|
border: medium outset ; |
||||
|
padding: 1em } |
||||
|
|
||||
|
div.system-message p.system-message-title { |
||||
|
color: red ; |
||||
|
font-weight: bold } |
||||
|
|
||||
|
div.topic { |
||||
|
margin: 2em } |
||||
|
|
||||
|
h1.section-subtitle, h2.section-subtitle, h3.section-subtitle, |
||||
|
h4.section-subtitle, h5.section-subtitle, h6.section-subtitle { |
||||
|
margin-top: 0.4em } |
||||
|
|
||||
|
h1.title { |
||||
|
text-align: center } |
||||
|
|
||||
|
h2.subtitle { |
||||
|
text-align: center } |
||||
|
|
||||
|
hr.docutils { |
||||
|
width: 75% } |
||||
|
|
||||
|
img.align-left, .figure.align-left, object.align-left, table.align-left { |
||||
|
clear: left ; |
||||
|
float: left ; |
||||
|
margin-right: 1em } |
||||
|
|
||||
|
img.align-right, .figure.align-right, object.align-right, table.align-right { |
||||
|
clear: right ; |
||||
|
float: right ; |
||||
|
margin-left: 1em } |
||||
|
|
||||
|
img.align-center, .figure.align-center, object.align-center { |
||||
|
display: block; |
||||
|
margin-left: auto; |
||||
|
margin-right: auto; |
||||
|
} |
||||
|
|
||||
|
table.align-center { |
||||
|
margin-left: auto; |
||||
|
margin-right: auto; |
||||
|
} |
||||
|
|
||||
|
.align-left { |
||||
|
text-align: left } |
||||
|
|
||||
|
.align-center { |
||||
|
clear: both ; |
||||
|
text-align: center } |
||||
|
|
||||
|
.align-right { |
||||
|
text-align: right } |
||||
|
|
||||
|
/* reset inner alignment in figures */ |
||||
|
div.align-right { |
||||
|
text-align: inherit } |
||||
|
|
||||
|
/* div.align-center * { */ |
||||
|
/* text-align: left } */ |
||||
|
|
||||
|
.align-top { |
||||
|
vertical-align: top } |
||||
|
|
||||
|
.align-middle { |
||||
|
vertical-align: middle } |
||||
|
|
||||
|
.align-bottom { |
||||
|
vertical-align: bottom } |
||||
|
|
||||
|
ol.simple, ul.simple { |
||||
|
margin-bottom: 1em } |
||||
|
|
||||
|
ol.arabic { |
||||
|
list-style: decimal } |
||||
|
|
||||
|
ol.loweralpha { |
||||
|
list-style: lower-alpha } |
||||
|
|
||||
|
ol.upperalpha { |
||||
|
list-style: upper-alpha } |
||||
|
|
||||
|
ol.lowerroman { |
||||
|
list-style: lower-roman } |
||||
|
|
||||
|
ol.upperroman { |
||||
|
list-style: upper-roman } |
||||
|
|
||||
|
p.attribution { |
||||
|
text-align: right ; |
||||
|
margin-left: 50% } |
||||
|
|
||||
|
p.caption { |
||||
|
font-style: italic } |
||||
|
|
||||
|
p.credits { |
||||
|
font-style: italic ; |
||||
|
font-size: smaller } |
||||
|
|
||||
|
p.label { |
||||
|
white-space: nowrap } |
||||
|
|
||||
|
p.rubric { |
||||
|
font-weight: bold ; |
||||
|
font-size: larger ; |
||||
|
color: maroon ; |
||||
|
text-align: center } |
||||
|
|
||||
|
p.sidebar-title { |
||||
|
font-family: sans-serif ; |
||||
|
font-weight: bold ; |
||||
|
font-size: larger } |
||||
|
|
||||
|
p.sidebar-subtitle { |
||||
|
font-family: sans-serif ; |
||||
|
font-weight: bold } |
||||
|
|
||||
|
p.topic-title { |
||||
|
font-weight: bold } |
||||
|
|
||||
|
pre.address { |
||||
|
margin-bottom: 0 ; |
||||
|
margin-top: 0 ; |
||||
|
font: inherit } |
||||
|
|
||||
|
pre.literal-block, pre.doctest-block, pre.math, pre.code { |
||||
|
margin-left: 2em ; |
||||
|
margin-right: 2em } |
||||
|
|
||||
|
pre.code .ln { color: grey; } /* line numbers */ |
||||
|
pre.code, code { background-color: #eeeeee } |
||||
|
pre.code .comment, code .comment { color: #5C6576 } |
||||
|
pre.code .keyword, code .keyword { color: #3B0D06; font-weight: bold } |
||||
|
pre.code .literal.string, code .literal.string { color: #0C5404 } |
||||
|
pre.code .name.builtin, code .name.builtin { color: #352B84 } |
||||
|
pre.code .deleted, code .deleted { background-color: #DEB0A1} |
||||
|
pre.code .inserted, code .inserted { background-color: #A3D289} |
||||
|
|
||||
|
span.classifier { |
||||
|
font-family: sans-serif ; |
||||
|
font-style: oblique } |
||||
|
|
||||
|
span.classifier-delimiter { |
||||
|
font-family: sans-serif ; |
||||
|
font-weight: bold } |
||||
|
|
||||
|
span.interpreted { |
||||
|
font-family: sans-serif } |
||||
|
|
||||
|
span.option { |
||||
|
white-space: nowrap } |
||||
|
|
||||
|
span.pre { |
||||
|
white-space: pre } |
||||
|
|
||||
|
span.problematic { |
||||
|
color: red } |
||||
|
|
||||
|
span.section-subtitle { |
||||
|
/* font-size relative to parent (h1..h6 element) */ |
||||
|
font-size: 80% } |
||||
|
|
||||
|
table.citation { |
||||
|
border-left: solid 1px gray; |
||||
|
margin-left: 1px } |
||||
|
|
||||
|
table.docinfo { |
||||
|
margin: 2em 4em } |
||||
|
|
||||
|
table.docutils { |
||||
|
margin-top: 0.5em ; |
||||
|
margin-bottom: 0.5em } |
||||
|
|
||||
|
table.footnote { |
||||
|
border-left: solid 1px black; |
||||
|
margin-left: 1px } |
||||
|
|
||||
|
table.docutils td, table.docutils th, |
||||
|
table.docinfo td, table.docinfo th { |
||||
|
padding-left: 0.5em ; |
||||
|
padding-right: 0.5em ; |
||||
|
vertical-align: top } |
||||
|
|
||||
|
table.docutils th.field-name, table.docinfo th.docinfo-name { |
||||
|
font-weight: bold ; |
||||
|
text-align: left ; |
||||
|
white-space: nowrap ; |
||||
|
padding-left: 0 } |
||||
|
|
||||
|
/* "booktabs" style (no vertical lines) */ |
||||
|
table.docutils.booktabs { |
||||
|
border: 0px; |
||||
|
border-top: 2px solid; |
||||
|
border-bottom: 2px solid; |
||||
|
border-collapse: collapse; |
||||
|
} |
||||
|
table.docutils.booktabs * { |
||||
|
border: 0px; |
||||
|
} |
||||
|
table.docutils.booktabs th { |
||||
|
border-bottom: thin solid; |
||||
|
text-align: left; |
||||
|
} |
||||
|
|
||||
|
h1 tt.docutils, h2 tt.docutils, h3 tt.docutils, |
||||
|
h4 tt.docutils, h5 tt.docutils, h6 tt.docutils { |
||||
|
font-size: 100% } |
||||
|
|
||||
|
ul.auto-toc { |
||||
|
list-style-type: none } |
||||
|
|
||||
|
</style> |
||||
|
</head> |
||||
|
<body> |
||||
|
<div class="document" id="loyalty-program"> |
||||
|
<h1 class="title">Loyalty Program</h1> |
||||
|
|
||||
|
<!-- !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! |
||||
|
!! This file is generated by oca-gen-addon-readme !! |
||||
|
!! changes will be overwritten. !! |
||||
|
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! --> |
||||
|
<p><a class="reference external" href="https://odoo-community.org/page/development-status"><img alt="Beta" src="https://img.shields.io/badge/maturity-Beta-yellow.png" /></a> <a class="reference external" href="http://www.gnu.org/licenses/agpl-3.0-standalone.html"><img alt="License: AGPL-3" src="https://img.shields.io/badge/licence-AGPL--3-blue.png" /></a> <a class="reference external" href="https://github.com/OCA/pos/tree/11.0/pos_loyalty"><img alt="OCA/pos" src="https://img.shields.io/badge/github-OCA%2Fpos-lightgray.png?logo=github" /></a> <a class="reference external" href="https://translation.odoo-community.org/projects/pos-11-0/pos-11-0-pos_loyalty"><img alt="Translate me on Weblate" src="https://img.shields.io/badge/weblate-Translate%20me-F47D42.png" /></a> <a class="reference external" href="https://runbot.odoo-community.org/runbot/184/11.0"><img alt="Try me on Runbot" src="https://img.shields.io/badge/runbot-Try%20me-875A7B.png" /></a></p> |
||||
|
<p>This module allows you to define a loyalty program in the point of sale, |
||||
|
where the customers earn loyalty points and get rewards.</p> |
||||
|
<p>This module is a forward-port to v10 of the pos_loyalty module from Odoo’s |
||||
|
saas-6 branch. |
||||
|
The functionality was moved to the Enterprise edition in later versions.</p> |
||||
|
<p><strong>Table of contents</strong></p> |
||||
|
<div class="contents local topic" id="contents"> |
||||
|
<ul class="simple"> |
||||
|
<li><a class="reference internal" href="#configuration" id="id1">Configuration</a></li> |
||||
|
<li><a class="reference internal" href="#usage" id="id2">Usage</a></li> |
||||
|
<li><a class="reference internal" href="#bug-tracker" id="id3">Bug Tracker</a></li> |
||||
|
<li><a class="reference internal" href="#credits" id="id4">Credits</a><ul> |
||||
|
<li><a class="reference internal" href="#authors" id="id5">Authors</a></li> |
||||
|
<li><a class="reference internal" href="#contributors" id="id6">Contributors</a></li> |
||||
|
<li><a class="reference internal" href="#maintainers" id="id7">Maintainers</a></li> |
||||
|
</ul> |
||||
|
</li> |
||||
|
</ul> |
||||
|
</div> |
||||
|
<div class="section" id="configuration"> |
||||
|
<h1><a class="toc-backref" href="#id1">Configuration</a></h1> |
||||
|
<p>To use this module, you need to:</p> |
||||
|
<ul class="simple"> |
||||
|
<li>Go to <em>Point of Sale > Configuration > Loyalty Programs</em> and define a new loyalty program with specific rules and rewards.</li> |
||||
|
<li>Assign the loyalty program to the desired Point of Sale.</li> |
||||
|
</ul> |
||||
|
</div> |
||||
|
<div class="section" id="usage"> |
||||
|
<h1><a class="toc-backref" href="#id2">Usage</a></h1> |
||||
|
<p>The Loyalty Program defines rules for acquiring points and rewards on which they can be spent.</p> |
||||
|
<p>Rules can be defined globally for all products (fields on loyalty.program) and / or rules that are applied only on specific product or PoS category (loyalty.rule records) on a <em>points per product sold</em> or <em>points per currency spent</em> basis. The specific rules (loyalty.rule) can be defined as cumulative, which means that they will be aggregated with other matching rules (loyalty.rule records and loyalty.program fields). In the case of non-cumulative rules only the points from that one matching rule are used. Additionally, <em>fixed points per order</em> can be added which are applied regardless of whether or not cumulative or non-cumulative rules were applied also.</p> |
||||
|
<p>Rewards can be of three types:</p> |
||||
|
<ul class="simple"> |
||||
|
<li><em>Gift</em> - give a single unit of product for free</li> |
||||
|
<li><em>Discount</em> - give a discount to the whole order. It should be added at the end of the order so that the correct total price is used.</li> |
||||
|
<li><em>Resale</em> - allow for customer to sell back his earned points. These are calculated by setting the price on the Resale product (<em>resale_product.list_price</em> * <em>customer.loyalty_points</em>)</li> |
||||
|
</ul> |
||||
|
<p>All rewards can define how many points they cost (point_cost) and how many are needed so that the customer can become eligable for the reward (minimum_points). for Gift and Discount rewards minimum_points are considered only if they are greater then the point_cost for that reward (minimum_points > point_cost). For Resale products only minimum_points can be used.</p> |
||||
|
</div> |
||||
|
<div class="section" id="bug-tracker"> |
||||
|
<h1><a class="toc-backref" href="#id3">Bug Tracker</a></h1> |
||||
|
<p>Bugs are tracked on <a class="reference external" href="https://github.com/OCA/pos/issues">GitHub Issues</a>. |
||||
|
In case of trouble, please check there if your issue has already been reported. |
||||
|
If you spotted it first, help us smashing it by providing a detailed and welcomed |
||||
|
<a class="reference external" href="https://github.com/OCA/pos/issues/new?body=module:%20pos_loyalty%0Aversion:%2011.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**">feedback</a>.</p> |
||||
|
<p>Do not contact contributors directly about support or help with technical issues.</p> |
||||
|
</div> |
||||
|
<div class="section" id="credits"> |
||||
|
<h1><a class="toc-backref" href="#id4">Credits</a></h1> |
||||
|
<div class="section" id="authors"> |
||||
|
<h2><a class="toc-backref" href="#id5">Authors</a></h2> |
||||
|
<ul class="simple"> |
||||
|
<li>OpenERP SA</li> |
||||
|
<li>RGB Consulting SL</li> |
||||
|
<li>Lambda IS</li> |
||||
|
</ul> |
||||
|
</div> |
||||
|
<div class="section" id="contributors"> |
||||
|
<h2><a class="toc-backref" href="#id6">Contributors</a></h2> |
||||
|
<ul class="simple"> |
||||
|
<li>RGB Consulting SL (<a class="reference external" href="http://www.rgbconsulting.com">http://www.rgbconsulting.com</a>)</li> |
||||
|
<li>Forward-port from Odoo SA saas-6 branch</li> |
||||
|
<li>Kiril Vangelovski <<a class="reference external" href="mailto:kiril@lambda-is.com">kiril@lambda-is.com</a>></li> |
||||
|
</ul> |
||||
|
</div> |
||||
|
<div class="section" id="maintainers"> |
||||
|
<h2><a class="toc-backref" href="#id7">Maintainers</a></h2> |
||||
|
<p>This module is maintained by the OCA.</p> |
||||
|
<a class="reference external image-reference" href="https://odoo-community.org"><img alt="Odoo Community Association" src="https://odoo-community.org/logo.png" /></a> |
||||
|
<p>OCA, or the Odoo Community Association, is a nonprofit organization whose |
||||
|
mission is to support the collaborative development of Odoo features and |
||||
|
promote its widespread use.</p> |
||||
|
<p>This module is part of the <a class="reference external" href="https://github.com/OCA/pos/tree/11.0/pos_loyalty">OCA/pos</a> project on GitHub.</p> |
||||
|
<p>You are welcome to contribute. To learn how please visit <a class="reference external" href="https://odoo-community.org/page/Contribute">https://odoo-community.org/page/Contribute</a>.</p> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
</body> |
||||
|
</html> |
@ -0,0 +1,21 @@ |
|||||
|
|
||||
|
.pos .order .summary .loyalty-points{ |
||||
|
margin-left: 20px; |
||||
|
float: left; |
||||
|
padding: 10px; |
||||
|
max-width: 216px; |
||||
|
text-align: left; |
||||
|
color: #6EC89B; |
||||
|
background: rgba(110, 200, 155, 0.17); |
||||
|
border-radius: 3px; |
||||
|
} |
||||
|
.pos .order .summary .loyalty-points.negative{ |
||||
|
color: #C86E6E; |
||||
|
background: rgba(200, 110, 110, 0.17); |
||||
|
} |
||||
|
.pos .order .summary .loyalty-points-total { |
||||
|
border-top: solid 2px; |
||||
|
text-align: center; |
||||
|
padding-top: 4px; |
||||
|
margin-top: 4px; |
||||
|
} |
@ -0,0 +1,477 @@ |
|||||
|
/* Copyright 2004-2010 OpenERP SA |
||||
|
* Copyright 2017 RGB Consulting S.L. (https://www.rgbconsulting.com)
|
||||
|
* License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). */
|
||||
|
|
||||
|
odoo.define('pos_loyalty.loyalty_program', function(require) { |
||||
|
"use strict" |
||||
|
|
||||
|
var models = require('point_of_sale.models'); |
||||
|
var screens = require('point_of_sale.screens'); |
||||
|
|
||||
|
var utils = require('web.utils'); |
||||
|
var round_pr = utils.round_precision; |
||||
|
|
||||
|
var core = require('web.core'); |
||||
|
var QWeb = core.qweb; |
||||
|
var _t = core._t; |
||||
|
|
||||
|
models.load_fields('res.partner', 'loyalty_points'); |
||||
|
|
||||
|
models.load_models([{ |
||||
|
model: 'loyalty.program', |
||||
|
condition: function(self) { |
||||
|
return !!self.config.loyalty_id[0]; |
||||
|
}, |
||||
|
fields: ['name', 'pp_currency', 'pp_product', 'pp_order', 'rounding'], |
||||
|
domain: function(self) { |
||||
|
return [ |
||||
|
['id', '=', self.config.loyalty_id[0]] |
||||
|
]; |
||||
|
}, |
||||
|
loaded: function(self, loyalties) { |
||||
|
self.loyalty = loyalties[0]; |
||||
|
}, |
||||
|
}, { |
||||
|
model: 'loyalty.rule', |
||||
|
condition: function(self) { |
||||
|
return !!self.loyalty; |
||||
|
}, |
||||
|
fields: ['name', 'type', 'product_id', 'category_id', 'cumulative', 'pp_product', 'pp_currency'], |
||||
|
domain: function(self) { |
||||
|
return [ |
||||
|
['loyalty_program_id', '=', self.loyalty.id] |
||||
|
]; |
||||
|
}, |
||||
|
loaded: function(self, rules) { |
||||
|
|
||||
|
self.loyalty.rules = rules; |
||||
|
self.loyalty.rules_by_product_id = {}; |
||||
|
self.loyalty.rules_by_category_id = {}; |
||||
|
|
||||
|
function update_rules(rules, rule, id) { |
||||
|
if (!rules[id]) { |
||||
|
rules[id] = [rule]; |
||||
|
} else if (rule.cumulative) { |
||||
|
rules[id].unshift(rule); |
||||
|
} else { |
||||
|
rules[id].push(rule); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
_.each(rules, function(rule) { |
||||
|
if (rule.type === 'product') |
||||
|
update_rules(self.loyalty.rules_by_product_id, rule, rule.product_id[0]) |
||||
|
else if (rule.type === 'category') |
||||
|
update_rules(self.loyalty.rules_by_category_id, rule, rule.category_id[0]); |
||||
|
}); |
||||
|
}, |
||||
|
}, { |
||||
|
model: 'loyalty.reward', |
||||
|
condition: function(self) { |
||||
|
return !!self.loyalty; |
||||
|
}, |
||||
|
fields: ['name', 'type', 'minimum_points', 'gift_product_id', 'point_cost', 'discount_product_id', 'discount', 'discount_max', 'point_product_id'], |
||||
|
domain: function(self) { |
||||
|
return [ |
||||
|
['loyalty_program_id', '=', self.loyalty.id] |
||||
|
]; |
||||
|
}, |
||||
|
loaded: function(self, rewards) { |
||||
|
self.loyalty.rewards = rewards; |
||||
|
self.loyalty.rewards_by_id = {}; |
||||
|
for (var i = 0; i < rewards.length; i++) { |
||||
|
self.loyalty.rewards_by_id[rewards[i].id] = rewards[i]; |
||||
|
} |
||||
|
}, |
||||
|
}, ], { |
||||
|
'after': 'product.product' |
||||
|
}); |
||||
|
|
||||
|
var _orderline_super = models.Orderline.prototype; |
||||
|
models.Orderline = models.Orderline.extend({ |
||||
|
get_reward: function() { |
||||
|
return this.pos.loyalty.rewards_by_id[this.reward_id]; |
||||
|
}, |
||||
|
set_reward: function(reward) { |
||||
|
this.reward_id = reward.id; |
||||
|
}, |
||||
|
export_as_JSON: function() { |
||||
|
var json = _orderline_super.export_as_JSON.apply(this, arguments); |
||||
|
json.reward_id = this.reward_id; |
||||
|
return json; |
||||
|
}, |
||||
|
init_from_JSON: function(json) { |
||||
|
_orderline_super.init_from_JSON.apply(this, arguments); |
||||
|
this.reward_id = json.reward_id; |
||||
|
}, |
||||
|
}); |
||||
|
|
||||
|
var _order_super = models.Order.prototype; |
||||
|
models.Order = models.Order.extend({ |
||||
|
|
||||
|
/* The total of points won, excluding the points spent on rewards */ |
||||
|
get_won_points: function() { |
||||
|
if (!this.pos.loyalty || !this.get_client()) { |
||||
|
return 0; |
||||
|
} |
||||
|
|
||||
|
var orderLines = this.get_orderlines(); |
||||
|
var rounding = this.pos.loyalty.rounding; |
||||
|
|
||||
|
var product_sold = 0; |
||||
|
var total_sold = 0; |
||||
|
var total_points = 0; |
||||
|
|
||||
|
for (var i = 0; i < orderLines.length; i++) { |
||||
|
var line = orderLines[i]; |
||||
|
var product = line.get_product(); |
||||
|
var rules = this.pos.loyalty.rules_by_product_id[product.id] || []; |
||||
|
var overriden = false; |
||||
|
|
||||
|
if (line.get_reward()) { // Reward products are ignored
|
||||
|
continue; |
||||
|
} |
||||
|
|
||||
|
for (var j = 0; j < rules.length; j++) { |
||||
|
var rule = rules[j]; |
||||
|
total_points += round_pr(line.get_quantity() * rule.pp_product, rounding); |
||||
|
total_points += round_pr(line.get_price_with_tax() * rule.pp_currency, rounding); |
||||
|
// if affected by a non cumulative rule, skip the others. (non cumulative rules are put
|
||||
|
// at the beginning of the list when they are loaded )
|
||||
|
if (!rule.cumulative) { |
||||
|
overriden = true; |
||||
|
break; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// Test the category rules
|
||||
|
if (product.pos_categ_id) { |
||||
|
var category = this.pos.db.get_category_by_id(product.pos_categ_id[0]); |
||||
|
while (category && !overriden) { |
||||
|
var rules = this.pos.loyalty.rules_by_category_id[category.id] || []; |
||||
|
for (var j = 0; j < rules.length; j++) { |
||||
|
var rule = rules[j]; |
||||
|
total_points += round_pr(line.get_quantity() * rule.pp_product, rounding); |
||||
|
total_points += round_pr(line.get_price_with_tax() * rule.pp_currency, rounding); |
||||
|
if (!rule.cumulative) { |
||||
|
overriden = true; |
||||
|
break; |
||||
|
} |
||||
|
} |
||||
|
var _category = category; |
||||
|
category = this.pos.db.get_category_by_id(this.pos.db.get_category_parent_id(category.id)); |
||||
|
if (_category === category) { |
||||
|
break; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
if (!overriden) { |
||||
|
product_sold += line.get_quantity(); |
||||
|
total_sold += line.get_price_with_tax(); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
total_points += round_pr(total_sold * this.pos.loyalty.pp_currency, rounding); |
||||
|
total_points += round_pr(product_sold * this.pos.loyalty.pp_product, rounding); |
||||
|
total_points += round_pr(this.pos.loyalty.pp_order, rounding); |
||||
|
|
||||
|
return total_points; |
||||
|
}, |
||||
|
|
||||
|
/* The total number of points spent on rewards */ |
||||
|
get_spent_points: function() { |
||||
|
if (!this.pos.loyalty || !this.get_client()) { |
||||
|
return 0; |
||||
|
} else { |
||||
|
var lines = this.get_orderlines(); |
||||
|
var rounding = this.pos.loyalty.rounding; |
||||
|
var points = 0; |
||||
|
|
||||
|
for (var i = 0; i < lines.length; i++) { |
||||
|
var line = lines[i]; |
||||
|
var reward = line.get_reward(); |
||||
|
if (reward) { |
||||
|
if (reward.type === 'gift') { |
||||
|
points += round_pr(line.get_quantity() * reward.point_cost, rounding); |
||||
|
} else if (reward.type === 'discount') { |
||||
|
points += reward.point_cost; |
||||
|
} else if (reward.type === 'resale') { |
||||
|
points += (-line.get_quantity()); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
return points; |
||||
|
} |
||||
|
}, |
||||
|
|
||||
|
/* The total number of points lost or won after the order is validated */ |
||||
|
get_new_points: function() { |
||||
|
if (!this.pos.loyalty || !this.get_client()) { |
||||
|
return 0; |
||||
|
} else { |
||||
|
return round_pr(this.get_won_points() - this.get_spent_points(), this.pos.loyalty.rounding); |
||||
|
} |
||||
|
}, |
||||
|
|
||||
|
/* The total number of points that the customer will have after this order is validated */ |
||||
|
get_new_total_points: function() { |
||||
|
if (!this.pos.loyalty || !this.get_client()) { |
||||
|
return 0; |
||||
|
} else { |
||||
|
return round_pr(this.get_client().loyalty_points + this.get_new_points(), this.pos.loyalty.rounding); |
||||
|
} |
||||
|
}, |
||||
|
|
||||
|
/* The number of loyalty points currently owned by the customer */ |
||||
|
get_current_points: function() { |
||||
|
return this.get_client() ? this.get_client().loyalty_points : 0; |
||||
|
}, |
||||
|
|
||||
|
/* The total number of points spendable on rewards */ |
||||
|
get_spendable_points: function() { |
||||
|
if (!this.pos.loyalty || !this.get_client()) { |
||||
|
return 0; |
||||
|
} else { |
||||
|
return round_pr(this.get_client().loyalty_points - this.get_spent_points(), this.pos.loyalty.rounding); |
||||
|
} |
||||
|
}, |
||||
|
|
||||
|
has_discount_reward: function() { |
||||
|
var res = false; |
||||
|
var lines = this.get_orderlines(); |
||||
|
|
||||
|
for (var i = 0; i < lines.length; i++) { |
||||
|
var line = lines[i]; |
||||
|
var reward = line.get_reward(); |
||||
|
if (reward && reward.type === 'discount') { |
||||
|
res = true; |
||||
|
break; |
||||
|
} |
||||
|
} |
||||
|
return res; |
||||
|
}, |
||||
|
|
||||
|
/* The list of rewards that the current customer can get */ |
||||
|
get_available_rewards: function() { |
||||
|
var client = this.get_client(); |
||||
|
if (!client) { |
||||
|
return []; |
||||
|
} |
||||
|
var rewards = []; |
||||
|
var discount_reward_set = this.has_discount_reward(); |
||||
|
for (var i = 0; i < this.pos.loyalty.rewards.length; i++) { |
||||
|
var reward = this.pos.loyalty.rewards[i]; |
||||
|
|
||||
|
if (reward.minimum_points > this.get_spendable_points()) { |
||||
|
continue; |
||||
|
} else if (reward.type === 'gift' && |
||||
|
reward.point_cost > this.get_spendable_points()) { |
||||
|
continue; |
||||
|
} else if (reward.type === 'discount' && |
||||
|
(discount_reward_set || reward.point_cost > this.get_spendable_points())) { |
||||
|
continue; |
||||
|
} |
||||
|
rewards.push(reward); |
||||
|
} |
||||
|
return rewards; |
||||
|
}, |
||||
|
|
||||
|
apply_reward: function(reward) { |
||||
|
var client = this.get_client(); |
||||
|
if (!client) { |
||||
|
return; |
||||
|
} else if (reward.type === 'gift') { |
||||
|
var product = this.pos.db.get_product_by_id(reward.gift_product_id[0]); |
||||
|
|
||||
|
if (!product) { |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
this.add_product(product, { |
||||
|
price: 0, |
||||
|
quantity: 1, |
||||
|
merge: false, |
||||
|
extras: { |
||||
|
reward_id: reward.id |
||||
|
}, |
||||
|
}); |
||||
|
|
||||
|
} else if (reward.type === 'discount') { |
||||
|
|
||||
|
var crounding = this.pos.currency.rounding; |
||||
|
var order_total = this.get_total_with_tax(); |
||||
|
var discount = round_pr(order_total * reward.discount, crounding); |
||||
|
var discount_max = reward.discount_max |
||||
|
|
||||
|
if (discount_max && discount > discount_max) { |
||||
|
discount = discount_max; |
||||
|
} |
||||
|
|
||||
|
var product = this.pos.db.get_product_by_id(reward.discount_product_id[0]); |
||||
|
|
||||
|
if (!product) { |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
this.add_product(product, { |
||||
|
price: -discount, |
||||
|
quantity: 1, |
||||
|
merge: false, |
||||
|
extras: { |
||||
|
reward_id: reward.id |
||||
|
}, |
||||
|
}); |
||||
|
|
||||
|
} else if (reward.type === 'resale') { |
||||
|
|
||||
|
var lrounding = this.pos.loyalty.rounding; |
||||
|
var crounding = this.pos.currency.rounding; |
||||
|
var spendable = this.get_spendable_points(); |
||||
|
|
||||
|
var order_total = this.get_total_with_tax(); |
||||
|
var product = this.pos.db.get_product_by_id(reward.point_product_id[0]); |
||||
|
|
||||
|
if (!product) { |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
if (round_pr(spendable * product.price, crounding) > order_total) { |
||||
|
spendable = round_pr(Math.floor(order_total / product.price), lrounding); |
||||
|
} |
||||
|
|
||||
|
if (spendable < 0.00001) { |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
this.add_product(product, { |
||||
|
quantity: -spendable, |
||||
|
merge: false, |
||||
|
extras: { |
||||
|
reward_id: reward.id |
||||
|
}, |
||||
|
}); |
||||
|
} |
||||
|
}, |
||||
|
|
||||
|
finalize: function() { |
||||
|
var client = this.get_client(); |
||||
|
if (client) { |
||||
|
client.loyalty_points = this.get_new_total_points(); |
||||
|
this.pos.gui.screen_instances.clientlist.partner_cache.clear_node(client.id); |
||||
|
} |
||||
|
_order_super.finalize.apply(this, arguments); |
||||
|
}, |
||||
|
|
||||
|
export_for_printing: function() { |
||||
|
var json = _order_super.export_for_printing.apply(this, arguments); |
||||
|
if (this.pos.loyalty && this.get_client()) { |
||||
|
json.loyalty = { |
||||
|
rounding: this.pos.loyalty.rounding || 1, |
||||
|
name: this.pos.loyalty.name, |
||||
|
client: this.get_client().name, |
||||
|
points_won: this.get_won_points(), |
||||
|
points_spent: this.get_spent_points(), |
||||
|
points_total: this.get_new_total_points(), |
||||
|
}; |
||||
|
} |
||||
|
return json; |
||||
|
}, |
||||
|
|
||||
|
export_as_JSON: function() { |
||||
|
var json = _order_super.export_as_JSON.apply(this, arguments); |
||||
|
json.loyalty_points = this.get_new_points(); |
||||
|
return json; |
||||
|
}, |
||||
|
}); |
||||
|
|
||||
|
var LoyaltyButton = screens.ActionButtonWidget.extend({ |
||||
|
template: 'LoyaltyButton', |
||||
|
button_click: function() { |
||||
|
var self = this; |
||||
|
var order = this.pos.get_order(); |
||||
|
var client = order.get_client(); |
||||
|
if (!client) { |
||||
|
this.gui.show_screen('clientlist'); |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
var rewards = order.get_available_rewards(); |
||||
|
if (rewards.length === 0) { |
||||
|
this.gui.show_popup('error', { |
||||
|
'title': _t('No Rewards Available'), |
||||
|
'body': _t('There are no rewards available for this customer as part of the loyalty program'), |
||||
|
}); |
||||
|
} else if (rewards.length === 1 && this.pos.loyalty.rewards.length === 1) { |
||||
|
order.apply_reward(rewards[0]); |
||||
|
} else { |
||||
|
var list = []; |
||||
|
for (var i = 0; i < rewards.length; i++) { |
||||
|
list.push({ |
||||
|
label: rewards[i].name, |
||||
|
item: rewards[i], |
||||
|
}); |
||||
|
} |
||||
|
this.gui.show_popup('selection', { |
||||
|
'title': _t('Please select a reward'), |
||||
|
'list': list, |
||||
|
'confirm': function(reward) { |
||||
|
order.apply_reward(reward); |
||||
|
}, |
||||
|
}); |
||||
|
} |
||||
|
}, |
||||
|
}); |
||||
|
|
||||
|
screens.define_action_button({ |
||||
|
'name': 'loyalty', |
||||
|
'widget': LoyaltyButton, |
||||
|
'condition': function() { |
||||
|
return this.pos.loyalty && this.pos.loyalty.rewards.length; |
||||
|
}, |
||||
|
}); |
||||
|
|
||||
|
screens.OrderWidget.include({ |
||||
|
update_summary: function() { |
||||
|
this._super(); |
||||
|
|
||||
|
var order = this.pos.get_order(); |
||||
|
|
||||
|
var $loypoints = $(this.el).find('.summary .loyalty-points'); |
||||
|
|
||||
|
if (this.pos.loyalty && order.get_client()) { |
||||
|
var points_won = order.get_won_points(); |
||||
|
var points_spent = order.get_spent_points(); |
||||
|
var points_total = order.get_new_total_points(); |
||||
|
$loypoints.replaceWith($(QWeb.render('LoyaltyPoints', { |
||||
|
widget: this, |
||||
|
rounding: this.pos.loyalty.rounding, |
||||
|
points_won: points_won, |
||||
|
points_spent: points_spent, |
||||
|
points_total: points_total, |
||||
|
}))); |
||||
|
$loypoints = $(this.el).find('.summary .loyalty-points'); |
||||
|
$loypoints.removeClass('oe_hidden'); |
||||
|
|
||||
|
if (points_total < 0) { |
||||
|
$loypoints.addClass('negative'); |
||||
|
} else { |
||||
|
$loypoints.removeClass('negative'); |
||||
|
} |
||||
|
} else { |
||||
|
$loypoints.empty(); |
||||
|
$loypoints.addClass('oe_hidden'); |
||||
|
} |
||||
|
|
||||
|
if (this.pos.loyalty && |
||||
|
order.get_client() && |
||||
|
this.getParent().action_buttons && |
||||
|
this.getParent().action_buttons.loyalty) { |
||||
|
|
||||
|
var rewards = order.get_available_rewards(); |
||||
|
this.getParent().action_buttons.loyalty.highlight(!!rewards.length); |
||||
|
} |
||||
|
}, |
||||
|
}); |
||||
|
}); |
@ -0,0 +1,170 @@ |
|||||
|
// Copyright 2004-2018 Odoo SA
|
||||
|
// Copyright 2018 Lambda IS DOOEL <https://www.lambda-is.com>
|
||||
|
// License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||
|
|
||||
|
odoo.define('pos_loyalty.tour.test_pos_loyalty', function(require) { |
||||
|
"use strict"; |
||||
|
|
||||
|
// Some of the steps are taken from the pos_basic_order tour in point_of_sale.
|
||||
|
// Added additional ones necessary for testing the rewards.
|
||||
|
|
||||
|
var Tour = require("web_tour.tour"); |
||||
|
|
||||
|
function add_customer(customer_name) { |
||||
|
return [{ |
||||
|
content: 'open customer screen', |
||||
|
trigger: '.button.set-customer', |
||||
|
}, { |
||||
|
content: 'choose customer ' + customer_name, |
||||
|
trigger: 'table.client-list tbody.client-list-contents tr.client-line td:contains("' + customer_name + '")', |
||||
|
}, { |
||||
|
content: 'select customer ' + customer_name, |
||||
|
trigger: '.button.next:contains("Set Customer")', |
||||
|
}, { |
||||
|
content: 'Check if customer ' + customer_name + ' is added', |
||||
|
trigger: '.button.set-customer:contains("' + customer_name + '")', |
||||
|
run: function() {}, // it's a check
|
||||
|
}]; |
||||
|
} |
||||
|
|
||||
|
function add_reward(reward_name) { |
||||
|
return [{ |
||||
|
content: 'open rewards screen', |
||||
|
trigger: '.control-button:contains("Rewards")', |
||||
|
}, { |
||||
|
content: 'choose reward', |
||||
|
trigger: '.selection-item:contains("' + reward_name + '")', |
||||
|
}] |
||||
|
} |
||||
|
|
||||
|
function add_product_to_order(product_name) { |
||||
|
return [{ |
||||
|
content: 'buy ' + product_name, |
||||
|
trigger: '.product-list .product-name:contains("' + product_name + '")', |
||||
|
}, { |
||||
|
content: 'the ' + product_name + ' have been added to the order', |
||||
|
trigger: '.order .product-name:contains("' + product_name + '")', |
||||
|
run: function() {}, // it's a check
|
||||
|
}]; |
||||
|
} |
||||
|
|
||||
|
function verify_order_product(product_name) { |
||||
|
return [{ |
||||
|
content: 'check if ' + product_name + ' is in order', |
||||
|
trigger: '.orderline .product-name:contains("' + product_name + '")', |
||||
|
run: function() {}, // it's a check
|
||||
|
}] |
||||
|
} |
||||
|
|
||||
|
function generate_keypad_steps(amount_str, keypad_selector) { |
||||
|
var i, steps = [], |
||||
|
current_char; |
||||
|
for (i = 0; i < amount_str.length; ++i) { |
||||
|
current_char = amount_str[i]; |
||||
|
steps.push({ |
||||
|
content: 'press ' + current_char + ' on payment keypad', |
||||
|
trigger: keypad_selector + ' .input-button:contains("' + current_char + '"):visible' |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
return steps; |
||||
|
} |
||||
|
|
||||
|
function generate_payment_screen_keypad_steps(amount_str) { |
||||
|
return generate_keypad_steps(amount_str, '.payment-numpad'); |
||||
|
} |
||||
|
|
||||
|
function generate_product_screen_keypad_steps(amount_str) { |
||||
|
return generate_keypad_steps(amount_str, '.numpad'); |
||||
|
} |
||||
|
|
||||
|
function verify_order_total(total_str) { |
||||
|
return [{ |
||||
|
content: 'order total contains ' + total_str, |
||||
|
trigger: '.order .total .value:contains("' + total_str + '")', |
||||
|
run: function() {}, // it's a check
|
||||
|
}]; |
||||
|
} |
||||
|
|
||||
|
function goto_payment_screen_and_select_payment_method() { |
||||
|
return [{ |
||||
|
content: "go to payment screen", |
||||
|
trigger: '.button.pay', |
||||
|
}, { |
||||
|
content: "pay with cash", |
||||
|
trigger: '.paymentmethod:contains("Cash")', |
||||
|
}]; |
||||
|
} |
||||
|
|
||||
|
function finish_order() { |
||||
|
return [{ |
||||
|
content: "validate the order", |
||||
|
trigger: '.button.next:visible', |
||||
|
}, { |
||||
|
content: "verify that the order is being sent to the backend", |
||||
|
trigger: ".js_connecting:visible", |
||||
|
run: function() {}, // it's a check
|
||||
|
}, { |
||||
|
content: "verify that the order has been succesfully sent to the backend", |
||||
|
trigger: ".js_connected:visible", |
||||
|
run: function() {}, // it's a check
|
||||
|
}, { |
||||
|
content: "next order", |
||||
|
trigger: '.button.next:visible', |
||||
|
}]; |
||||
|
} |
||||
|
|
||||
|
var steps = [{ |
||||
|
content: 'waiting for loading to finish', |
||||
|
trigger: '.o_main_content:has(.loader:hidden)', |
||||
|
run: function() {}, // it's a check
|
||||
|
}]; |
||||
|
|
||||
|
steps = steps.concat(add_customer('Agrolait')); |
||||
|
steps = steps.concat(add_product_to_order('Peaches')); |
||||
|
steps = steps.concat(verify_order_total('5.10')); |
||||
|
|
||||
|
steps = steps.concat(add_product_to_order('Peaches')); // buy another kg of peaches
|
||||
|
steps = steps.concat(verify_order_total('10.20')); |
||||
|
steps = steps.concat(goto_payment_screen_and_select_payment_method()); |
||||
|
steps = steps.concat(generate_payment_screen_keypad_steps("12.20")); |
||||
|
|
||||
|
steps = steps.concat([{ |
||||
|
content: "verify tendered", |
||||
|
trigger: '.col-tendered:contains("12.20")', |
||||
|
run: function() {}, // it's a check
|
||||
|
}, { |
||||
|
content: "verify change", |
||||
|
trigger: '.col-change:contains("2.00")', |
||||
|
run: function() {}, // it's a check
|
||||
|
}]); |
||||
|
|
||||
|
steps = steps.concat(finish_order()); |
||||
|
|
||||
|
Tour.register('test_pos_loyalty_acquire_points', { |
||||
|
test: true, |
||||
|
url: '/pos/web' |
||||
|
}, steps); |
||||
|
|
||||
|
steps = [{ |
||||
|
content: 'waiting for loading to finish', |
||||
|
trigger: '.o_main_content:has(.loader:hidden)', |
||||
|
run: function() {}, // it's a check
|
||||
|
}]; |
||||
|
steps = steps.concat(add_customer('Agrolait')); |
||||
|
steps = steps.concat(add_reward('Free Peaches')); |
||||
|
steps = steps.concat(verify_order_product('Peaches')); |
||||
|
steps = steps.concat(verify_order_total('0.00')); |
||||
|
steps = steps.concat(goto_payment_screen_and_select_payment_method()); |
||||
|
steps = steps.concat([{ |
||||
|
content: "verify tendered", |
||||
|
trigger: '.col-tendered:contains("0.00")', |
||||
|
run: function() {}, // it's a check
|
||||
|
}]); |
||||
|
steps = steps.concat(finish_order()); |
||||
|
|
||||
|
Tour.register('test_pos_loyalty_spend_points', { |
||||
|
test: true, |
||||
|
url: '/pos/web' |
||||
|
}, steps); |
||||
|
}) |
@ -0,0 +1,85 @@ |
|||||
|
<?xml version="1.0" encoding="UTF-8"?> |
||||
|
<templates id="template" xml:space="preserve"> |
||||
|
|
||||
|
<t t-name="LoyaltyPoints"> |
||||
|
<div class='loyalty-points'> |
||||
|
<div class='loyalty-points-title'>Points</div> |
||||
|
<t t-if='points_won'> |
||||
|
<div class="loyalty-points-won"> |
||||
|
<span class='value'>+<t t-esc='widget.format_pr(points_won,rounding)'/></span> |
||||
|
</div> |
||||
|
</t> |
||||
|
<t t-if='points_spent'> |
||||
|
<div class="loyalty-points-spent"> |
||||
|
<span class='value'>-<t t-esc='widget.format_pr(points_spent,rounding)'/></span> |
||||
|
</div> |
||||
|
</t> |
||||
|
<div class='loyalty-points-total'> |
||||
|
<span class='value'><t t-esc='widget.format_pr(points_total,rounding)' /></span> |
||||
|
</div> |
||||
|
</div> |
||||
|
</t> |
||||
|
|
||||
|
<t t-name="LoyaltyButton"> |
||||
|
<div class='control-button'> |
||||
|
<i class='fa fa-star' /> Rewards |
||||
|
</div> |
||||
|
</t> |
||||
|
|
||||
|
<t t-extend='OrderWidget'> |
||||
|
<t t-jquery='.summary' t-operation='prepend'> |
||||
|
<div class='loyalty-points oe_hidden'>.</div> |
||||
|
</t> |
||||
|
</t> |
||||
|
|
||||
|
<t t-extend='ClientLine'> |
||||
|
<t t-jquery='.client-line' t-operation='append'> |
||||
|
<td> |
||||
|
<t t-esc='widget.format_pr(partner.loyalty_points || 0, widget.pos.loyalty ? widget.pos.loyalty.rounding : 1.0)' /> |
||||
|
</td> |
||||
|
</t> |
||||
|
</t> |
||||
|
|
||||
|
<t t-extend="XmlReceipt"> |
||||
|
<t t-jquery='.before-footer' t-operation='append'> |
||||
|
<t t-if='receipt.loyalty'> |
||||
|
<div class='loyalty' value-decimals='2' value-autoint='on'> |
||||
|
<div>--------------------------------</div> |
||||
|
<br/> |
||||
|
<div size='double-height'><t t-esc='receipt.loyalty.name'/></div> |
||||
|
<br /> |
||||
|
<div><t t-esc='receipt.loyalty.client' /></div> |
||||
|
<br/> |
||||
|
<t t-if='receipt.loyalty.points_won'> |
||||
|
<line><left>Points Won</left><right><value><t t-esc='receipt.loyalty.points_won' /></value></right></line> |
||||
|
</t> |
||||
|
<t t-if='receipt.loyalty.points_spent'> |
||||
|
<line><left>Points Spent</left><right><value><t t-esc='receipt.loyalty.points_spent' /></value></right></line> |
||||
|
</t> |
||||
|
<t t-if='receipt.loyalty.points_total'> |
||||
|
<line><left>Total Points</left><right><value><t t-esc='receipt.loyalty.points_total' /></value></right></line> |
||||
|
</t> |
||||
|
<br /> |
||||
|
</div> |
||||
|
</t> |
||||
|
</t> |
||||
|
</t> |
||||
|
|
||||
|
<t t-extend='ClientDetails'> |
||||
|
<t t-jquery='.client-details-right' t-operation='prepend'> |
||||
|
<div class='client-detail'> |
||||
|
<span class='label'>Points</span> |
||||
|
<span class='detail client-points'> |
||||
|
<t t-esc='widget.format_pr(partner.loyalty_points || 0, widget.pos.loyalty ? widget.pos.loyalty.rounding : 1.0)' /> |
||||
|
</span> |
||||
|
</div> |
||||
|
</t> |
||||
|
</t> |
||||
|
|
||||
|
<t t-extend='ClientListScreenWidget'> |
||||
|
<t t-jquery='.client-list thead tr' t-operation='append'> |
||||
|
<th>Points</th> |
||||
|
</t> |
||||
|
</t> |
||||
|
|
||||
|
</templates> |
@ -0,0 +1,2 @@ |
|||||
|
|
||||
|
from . import test_pos_loyalty |
@ -0,0 +1,74 @@ |
|||||
|
# Copyright 2004-2018 Odoo SA |
||||
|
# Copyright 2018 Lambda IS DOOEL <https://www.lambda-is.com> |
||||
|
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). |
||||
|
|
||||
|
from odoo.api import Environment |
||||
|
from odoo.tests import HttpCase |
||||
|
|
||||
|
|
||||
|
class TestPOSLoyalty(HttpCase): |
||||
|
|
||||
|
def test_pos_loyalty(self): |
||||
|
cr = self.registry.cursor() |
||||
|
assert cr == self.registry.test_cr |
||||
|
env = Environment(cr, self.uid, {}) |
||||
|
main_pos_config = env.ref('point_of_sale.pos_config_main') |
||||
|
target_product = env.ref('point_of_sale.peche') |
||||
|
free_product = env.ref('point_of_sale.Onions') |
||||
|
customer = env.ref('base.res_partner_2') |
||||
|
loyalty_program = env['loyalty.program'].create({ |
||||
|
'name': 'foo', |
||||
|
'rule_ids': [(0, 0, { |
||||
|
'name': 'Peaches', |
||||
|
'type': 'product', |
||||
|
'product_id': target_product.id, |
||||
|
'pp_product': 10, |
||||
|
})], |
||||
|
'reward_ids': [(0, 0, { |
||||
|
'name': 'Free Peaches', |
||||
|
'type': 'gift', |
||||
|
'gift_product_id': target_product.id, |
||||
|
'point_cost': 20, |
||||
|
'minimum_points': 20, |
||||
|
}), (0, 0, { |
||||
|
'name': 'Free Onions', |
||||
|
'type': 'gift', |
||||
|
'gift_product_id': free_product.id, |
||||
|
'point_cost': 20, |
||||
|
'minimum_points': 20, |
||||
|
})] |
||||
|
}) |
||||
|
main_pos_config.write({'loyalty_id': loyalty_program.id}) |
||||
|
main_pos_config.open_session_cb() |
||||
|
|
||||
|
# needed because tests are run before the module is marked as |
||||
|
# installed. In js web will only load qweb coming from modules |
||||
|
# that are returned by the backend in module_boot. Without |
||||
|
# this you end up with js, css but no qweb. |
||||
|
env['ir.module.module'].search( |
||||
|
[('name', '=', 'pos_loyalty')], limit=1).state = 'installed' |
||||
|
|
||||
|
cr.release() |
||||
|
|
||||
|
# Process an order with 2kg of Peaches which should |
||||
|
# add 20 loyalty points |
||||
|
self.phantom_js("/pos/web", |
||||
|
"odoo.__DEBUG__.services['web_tour.tour'].run(" |
||||
|
"'test_pos_loyalty_acquire_points')", |
||||
|
"odoo.__DEBUG__.services['web_tour.tour'].tours" |
||||
|
".test_pos_loyalty_acquire_points.ready", |
||||
|
login="admin") |
||||
|
|
||||
|
self.assertEqual(customer.loyalty_points, 20) |
||||
|
|
||||
|
# Spend 20 loyalty points on "Free Peaches" reward |
||||
|
self.phantom_js("/pos/web", |
||||
|
"odoo.__DEBUG__.services['web_tour.tour'].run(" |
||||
|
"'test_pos_loyalty_spend_points')", |
||||
|
"odoo.__DEBUG__.services['web_tour.tour'].tours" |
||||
|
".test_pos_loyalty_spend_points.ready", |
||||
|
login="admin") |
||||
|
|
||||
|
customer_points = customer.read( |
||||
|
['loyalty_points'])[0]['loyalty_points'] |
||||
|
self.assertEqual(customer_points, 0) |
@ -0,0 +1,83 @@ |
|||||
|
<?xml version="1.0"?> |
||||
|
<odoo> |
||||
|
<record id="loyalty_program_form_view" model="ir.ui.view"> |
||||
|
<field name="name">loyalty.program.form</field> |
||||
|
<field name="model">loyalty.program</field> |
||||
|
<field name="arch" type="xml"> |
||||
|
<form string="Loyalty Program"> |
||||
|
<sheet> |
||||
|
<div class="oe_title"> |
||||
|
<label class="oe_edit_only" for="name"/> |
||||
|
<h1> |
||||
|
<field name="name" class="oe_inline"/> |
||||
|
</h1> |
||||
|
</div> |
||||
|
|
||||
|
<group> |
||||
|
<group> |
||||
|
<field name="pp_product"/> |
||||
|
<field name="pp_currency"/> |
||||
|
</group> |
||||
|
<group> |
||||
|
<field name="pp_order"/> |
||||
|
<field name="rounding"/> |
||||
|
</group> |
||||
|
</group> |
||||
|
|
||||
|
<separator string="Rules" colspan="4"/> |
||||
|
<p>Rules define how loyalty points are earned for specific products or categories</p> |
||||
|
<field name="rule_ids" colspan="4" nolabel="1"> |
||||
|
<tree string="Rules"> |
||||
|
<field name="name"/> |
||||
|
<field name="pp_product"/> |
||||
|
<field name="pp_currency"/> |
||||
|
<field name="cumulative"/> |
||||
|
</tree> |
||||
|
</field> |
||||
|
|
||||
|
<separator string="Rewards" colspan="4"/> |
||||
|
<p>Reward the customer with gifts or discounts for loyalty points</p> |
||||
|
<field name="reward_ids" colspan="4" nolabel="1"> |
||||
|
<tree string="Rewards"> |
||||
|
<field name="name"/> |
||||
|
<field name="type"/> |
||||
|
</tree> |
||||
|
</field> |
||||
|
</sheet> |
||||
|
</form> |
||||
|
</field> |
||||
|
</record> |
||||
|
|
||||
|
<record id="loyalty_program_tree_view" model="ir.ui.view"> |
||||
|
<field name="name">loyalty.program.tree</field> |
||||
|
<field name="model">loyalty.program</field> |
||||
|
<field name="arch" type="xml"> |
||||
|
<tree string="Loyalty Programs"> |
||||
|
<field name="name"/> |
||||
|
</tree> |
||||
|
</field> |
||||
|
</record> |
||||
|
|
||||
|
<record id="loyalty_program_action" model="ir.actions.act_window"> |
||||
|
<field name="name">Loyalty Programs</field> |
||||
|
<field name="type">ir.actions.act_window</field> |
||||
|
<field name="res_model">loyalty.program</field> |
||||
|
<field name="view_type">form</field> |
||||
|
<field name="view_mode">tree,form</field> |
||||
|
<field name="help" type="html"> |
||||
|
<p class="oe_view_nocontent_create"> |
||||
|
Click create to define a Loyalty Program. |
||||
|
</p> |
||||
|
<p> |
||||
|
Loyalty Programs allow you customers to earn points |
||||
|
and rewards when purchasing from your shops. |
||||
|
</p> |
||||
|
</field> |
||||
|
</record> |
||||
|
|
||||
|
<menuitem parent="point_of_sale.menu_point_config_product" |
||||
|
action="loyalty_program_action" |
||||
|
id="loyalty_program_menu" |
||||
|
sequence="30" |
||||
|
groups="point_of_sale.group_pos_manager"/> |
||||
|
</odoo> |
@ -0,0 +1,37 @@ |
|||||
|
<?xml version="1.0"?> |
||||
|
<odoo> |
||||
|
<record id="loyalty_reward_form_view" model="ir.ui.view"> |
||||
|
<field name="name">loyalty.reward.form</field> |
||||
|
<field name="model">loyalty.reward</field> |
||||
|
<field name="arch" type="xml"> |
||||
|
<form string="Loyalty Reward"> |
||||
|
<div class="oe_title"> |
||||
|
<label class="oe_edit_only" for="name"/> |
||||
|
<h1> |
||||
|
<field name="name" class="oe_inline"/> |
||||
|
</h1> |
||||
|
</div> |
||||
|
<group> |
||||
|
<field name="type"/> |
||||
|
</group> |
||||
|
<group > |
||||
|
<field name="gift_product_id" |
||||
|
attrs="{'invisible':[('type','!=','gift')], 'required':[('type','=','gift')]}"/> |
||||
|
<field name="discount" |
||||
|
attrs="{'invisible':[('type','!=','discount')]}"/> |
||||
|
<field name="discount_max" |
||||
|
attrs="{'invisible':[('type','!=','discount')]}"/> |
||||
|
<field name="discount_product_id" |
||||
|
attrs="{'invisible':[('type','!=','discount')], 'required':[('type','=','discount')]}"/> |
||||
|
<field name="point_product_id" |
||||
|
attrs="{'invisible': [('type','!=','resale')], 'required': [('type','=','resale')]}"/> |
||||
|
</group> |
||||
|
<group> |
||||
|
<field name="point_cost" |
||||
|
attrs="{'invisible':[('type','=','resale')]}"/> |
||||
|
<field name="minimum_points"/> |
||||
|
</group> |
||||
|
</form> |
||||
|
</field> |
||||
|
</record> |
||||
|
</odoo> |
@ -0,0 +1,31 @@ |
|||||
|
<?xml version="1.0"?> |
||||
|
<odoo> |
||||
|
<record id="loyalty_rule_form_view" model="ir.ui.view"> |
||||
|
<field name="name">loyalty.rule.form</field> |
||||
|
<field name="model">loyalty.rule</field> |
||||
|
<field name="arch" type="xml"> |
||||
|
<form string="Loyalty Rule"> |
||||
|
<div class="oe_title"> |
||||
|
<label class="oe_edit_only" for="name"/> |
||||
|
<h1> |
||||
|
<field name="name" class="oe_inline"/> |
||||
|
</h1> |
||||
|
</div> |
||||
|
<group> |
||||
|
<group> |
||||
|
<field name="type"/> |
||||
|
</group> |
||||
|
<group> |
||||
|
<field name="product_id" attrs="{'invisible': [('type','!=','product')], 'required': [('type','=','product')]}"/> |
||||
|
<field name="category_id" attrs="{'invisible': [('type','!=','category')], 'required': [('type','=','category')]}"/> |
||||
|
</group> |
||||
|
</group> |
||||
|
<group col="6"> |
||||
|
<field name="pp_product"/> |
||||
|
<field name="pp_currency"/> |
||||
|
<field name="cumulative"/> |
||||
|
</group> |
||||
|
</form> |
||||
|
</field> |
||||
|
</record> |
||||
|
</odoo> |
@ -0,0 +1,23 @@ |
|||||
|
<?xml version="1.0"?> |
||||
|
<odoo> |
||||
|
<record id="pos_config_view_form" model="ir.ui.view"> |
||||
|
<field name="name">pos.config.form</field> |
||||
|
<field name="model">pos.config</field> |
||||
|
<field name="inherit_id" ref="point_of_sale.pos_config_view_form"/> |
||||
|
<field name="arch" type="xml"> |
||||
|
<xpath expr="//div[@id='pricelist_setting']" position="after"> |
||||
|
<div class="col-xs-12 col-md-6 o_setting_box" title="abc"> |
||||
|
<div class="o_setting_right_pane"> |
||||
|
<label for="loyalty_id" string="Loyalty Program (OCA)"/> |
||||
|
<div class="text-muted"> |
||||
|
Loyalty program that will be available in this PoS |
||||
|
</div> |
||||
|
<div class="content-group mt16"> |
||||
|
<field name="loyalty_id"/> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
</xpath> |
||||
|
</field> |
||||
|
</record> |
||||
|
</odoo> |
@ -0,0 +1,15 @@ |
|||||
|
<?xml version="1.0"?> |
||||
|
<odoo> |
||||
|
<record id="pos_order_form_view" model="ir.ui.view"> |
||||
|
<field name="name">pos.order.form</field> |
||||
|
<field name="model">pos.order</field> |
||||
|
<field name="inherit_id" ref="point_of_sale.view_pos_pos_form"/> |
||||
|
<field name="arch" type="xml"> |
||||
|
<xpath expr="//page[@name='extra']" position="inside"> |
||||
|
<group name="loyalty" string="Loyalty Programs"> |
||||
|
<field name="loyalty_points"/> |
||||
|
</group> |
||||
|
</xpath> |
||||
|
</field> |
||||
|
</record> |
||||
|
</odoo> |
@ -0,0 +1,18 @@ |
|||||
|
<?xml version="1.0"?> |
||||
|
<odoo> |
||||
|
<record id="partner_property_form_view" model="ir.ui.view"> |
||||
|
<field name="name">partner.property.form</field> |
||||
|
<field name="model">res.partner</field> |
||||
|
<field name="inherit_id" ref="point_of_sale.view_partner_property_form"/> |
||||
|
<field name="arch" type="xml"> |
||||
|
<button name="%(point_of_sale.action_pos_pos_form)d" position="before"> |
||||
|
<button class="oe_stat_button" type="action" name="%(point_of_sale.action_pos_pos_form)d" |
||||
|
context="{'search_default_partner_id': active_id,'default_partner_id': active_id}" |
||||
|
attrs="{'invisible': ['|', ('customer', '=', False), ('pos_order_count', '=', 0)]}" |
||||
|
icon="fa-star"> |
||||
|
<field name="loyalty_points" widget="statinfo"/> |
||||
|
</button> |
||||
|
</button> |
||||
|
</field> |
||||
|
</record> |
||||
|
</odoo> |
@ -0,0 +1,9 @@ |
|||||
|
<?xml version="1.0" encoding="utf-8"?> |
||||
|
<odoo> |
||||
|
<template id="assets" inherit_id="point_of_sale.assets"> |
||||
|
<xpath expr="." position="inside"> |
||||
|
<script type="text/javascript" src="/pos_loyalty/static/src/js/pos.js"></script> |
||||
|
<link rel="stylesheet" href="/pos_loyalty/static/src/css/pos.css"/> |
||||
|
</xpath> |
||||
|
</template> |
||||
|
</odoo> |
@ -0,0 +1,86 @@ |
|||||
|
================ |
||||
|
Pos Mail Receipt |
||||
|
================ |
||||
|
|
||||
|
.. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! |
||||
|
!! This file is generated by oca-gen-addon-readme !! |
||||
|
!! changes will be overwritten. !! |
||||
|
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! |
||||
|
|
||||
|
.. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png |
||||
|
:target: https://odoo-community.org/page/development-status |
||||
|
:alt: Beta |
||||
|
.. |badge2| image:: https://img.shields.io/badge/licence-AGPL--3-blue.png |
||||
|
:target: http://www.gnu.org/licenses/agpl-3.0-standalone.html |
||||
|
:alt: License: AGPL-3 |
||||
|
.. |badge3| image:: https://img.shields.io/badge/github-OCA%2Fpos-lightgray.png?logo=github |
||||
|
:target: https://github.com/OCA/pos/tree/12.0/pos_mail_receipt |
||||
|
:alt: OCA/pos |
||||
|
.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png |
||||
|
:target: https://translation.odoo-community.org/projects/pos-12-0/pos-12-0-pos_mail_receipt |
||||
|
:alt: Translate me on Weblate |
||||
|
.. |badge5| image:: https://img.shields.io/badge/runbot-Try%20me-875A7B.png |
||||
|
:target: https://runbot.odoo-community.org/runbot/184/12.0 |
||||
|
:alt: Try me on Runbot |
||||
|
|
||||
|
|badge1| |badge2| |badge3| |badge4| |badge5| |
||||
|
|
||||
|
This modules allows you to send the PoS receipt by e-mail. |
||||
|
|
||||
|
Instead of printing the ticket you can choose to send it be e-mail. |
||||
|
If you know the customer's e-mail, it will use it. |
||||
|
If not you will be prompted for it. |
||||
|
|
||||
|
**Table of contents** |
||||
|
|
||||
|
.. contents:: |
||||
|
:local: |
||||
|
|
||||
|
Usage |
||||
|
===== |
||||
|
|
||||
|
#. Open a new PoS session. |
||||
|
#. Make an order and validate it. |
||||
|
#. You should see the company logo in the receipt preview. |
||||
|
|
||||
|
Bug Tracker |
||||
|
=========== |
||||
|
|
||||
|
Bugs are tracked on `GitHub Issues <https://github.com/OCA/pos/issues>`_. |
||||
|
In case of trouble, please check there if your issue has already been reported. |
||||
|
If you spotted it first, help us smashing it by providing a detailed and welcomed |
||||
|
`feedback <https://github.com/OCA/pos/issues/new?body=module:%20pos_mail_receipt%0Aversion:%2012.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**>`_. |
||||
|
|
||||
|
Do not contact contributors directly about support or help with technical issues. |
||||
|
|
||||
|
Credits |
||||
|
======= |
||||
|
|
||||
|
Authors |
||||
|
~~~~~~~ |
||||
|
|
||||
|
* Coop IT Easy SCRLfs |
||||
|
|
||||
|
Contributors |
||||
|
~~~~~~~~~~~~ |
||||
|
|
||||
|
* `Coop IT Easy SCRLfs <https://coopiteasy.be>`_: |
||||
|
|
||||
|
* Pierrick Brun |
||||
|
|
||||
|
Maintainers |
||||
|
~~~~~~~~~~~ |
||||
|
|
||||
|
This module is maintained by the OCA. |
||||
|
|
||||
|
.. image:: https://odoo-community.org/logo.png |
||||
|
:alt: Odoo Community Association |
||||
|
:target: https://odoo-community.org |
||||
|
|
||||
|
OCA, or the Odoo Community Association, is a nonprofit organization whose |
||||
|
mission is to support the collaborative development of Odoo features and |
||||
|
promote its widespread use. |
||||
|
|
||||
|
This module is part of the `OCA/pos <https://github.com/OCA/pos/tree/12.0/pos_mail_receipt>`_ project on GitHub. |
||||
|
|
||||
|
You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute. |
@ -0,0 +1 @@ |
|||||
|
from . import models |
@ -0,0 +1,14 @@ |
|||||
|
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). |
||||
|
|
||||
|
{ |
||||
|
"name": "Pos Mail Receipt", |
||||
|
"category": "Point Of Sale", |
||||
|
"version": "12.0.1.0.0", |
||||
|
"author": "Coop IT Easy SCRLfs, " "Odoo Community Association (OCA)", |
||||
|
"website": "https://github.com/OCA/pos", |
||||
|
"license": "AGPL-3", |
||||
|
"depends": ["point_of_sale"], |
||||
|
"data": ["templates/assets.xml", "data/email.xml"], |
||||
|
"qweb": ["static/src/xml/pos.xml"], |
||||
|
"installable": True, |
||||
|
} |
@ -0,0 +1,19 @@ |
|||||
|
<?xml version="1.0" encoding="utf-8"?> |
||||
|
<odoo> |
||||
|
|
||||
|
<data noupdate="0"> |
||||
|
<!--Email template --> |
||||
|
<record id="email_send_ticket" model="mail.template"> |
||||
|
<field name="name">Send Receipt</field> |
||||
|
<field name="email_from">${(object.user_id.email and '%s <%s>' % (object.user_id.name, object.user_id.email) or '')|safe}</field> |
||||
|
<field name="subject">${object.pos_reference}</field> |
||||
|
<field name="model_id" ref="point_of_sale.model_pos_order" /> |
||||
|
<field name="auto_delete" eval="True" /> |
||||
|
<field name="lang">${object.partner_id.lang}</field> |
||||
|
<field name="body_html"><![CDATA[ |
||||
|
Your Ticket ${object.pos_reference} |
||||
|
]]></field> |
||||
|
</record> |
||||
|
|
||||
|
</data> |
||||
|
</odoo> |
@ -0,0 +1,131 @@ |
|||||
|
# Translation of Odoo Server. |
||||
|
# This file contains the translation of the following modules: |
||||
|
# * pos_mail_receipt |
||||
|
# |
||||
|
msgid "" |
||||
|
msgstr "" |
||||
|
"Project-Id-Version: Odoo Server 12.0\n" |
||||
|
"Report-Msgid-Bugs-To: \n" |
||||
|
"POT-Creation-Date: 2019-12-17 14:32+0000\n" |
||||
|
"PO-Revision-Date: 2019-12-17 15:38+0100\n" |
||||
|
"Language-Team: \n" |
||||
|
"MIME-Version: 1.0\n" |
||||
|
"Content-Type: text/plain; charset=UTF-8\n" |
||||
|
"Content-Transfer-Encoding: 8bit\n" |
||||
|
"Plural-Forms: nplurals=2; plural=(n > 1);\n" |
||||
|
"X-Generator: Poedit 2.2.4\n" |
||||
|
"Last-Translator: \n" |
||||
|
"Language: fr\n" |
||||
|
|
||||
|
#. module: pos_mail_receipt |
||||
|
#: model:mail.template,subject:pos_mail_receipt.email_send_ticket |
||||
|
msgid "${object.pos_reference}" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_mail_receipt |
||||
|
#: model:mail.template,body_html:pos_mail_receipt.email_send_ticket |
||||
|
msgid "" |
||||
|
"<p style=\"margin:0px 0 1rem 0;font-size:13px;font-family:"Lucida " |
||||
|
"Grande", Helvetica, Verdana, Arial, sans-serif;\">\n" |
||||
|
"Your Ticket ${object.pos_reference}\n" |
||||
|
" </p>" |
||||
|
msgstr "" |
||||
|
"<p style=\"margin:0px 0 1rem 0;font-size:13px;font-family:"Lucida " |
||||
|
"Grande", Helvetica, Verdana, Arial, sans-serif;\">\n" |
||||
|
"Votre Ticket ${object.pos_reference}\n" |
||||
|
" </p>" |
||||
|
|
||||
|
#. module: pos_mail_receipt |
||||
|
#. openerp-web |
||||
|
#: code:addons/pos_mail_receipt/static/src/xml/pos.xml:25 |
||||
|
#, python-format |
||||
|
msgid "Cancel" |
||||
|
msgstr "Annuler" |
||||
|
|
||||
|
#. module: pos_mail_receipt |
||||
|
#: code:addons/pos_mail_receipt/models/pos_order.py:25 |
||||
|
#, python-format |
||||
|
msgid "Cannot send the ticket, no email address found for the client" |
||||
|
msgstr "" |
||||
|
"Impossible d'envoyer le ticket, pas d'adresse mail trouvée pour le " |
||||
|
"client" |
||||
|
|
||||
|
#. module: pos_mail_receipt |
||||
|
#. openerp-web |
||||
|
#: code:addons/pos_mail_receipt/static/src/js/screens.js:82 |
||||
|
#, python-format |
||||
|
msgid "Check your internet connection and try again." |
||||
|
msgstr "Vérifiez votre connexion internet et essayez à nouveau." |
||||
|
|
||||
|
#. module: pos_mail_receipt |
||||
|
#. openerp-web |
||||
|
#: code:addons/pos_mail_receipt/static/src/xml/pos.xml:22 |
||||
|
#, python-format |
||||
|
msgid "Confirm" |
||||
|
msgstr "Confirmer" |
||||
|
|
||||
|
#. module: pos_mail_receipt |
||||
|
#. openerp-web |
||||
|
#: code:addons/pos_mail_receipt/static/src/js/screens.js:28 |
||||
|
#, python-format |
||||
|
msgid "E-mail address to use" |
||||
|
msgstr "Adresse mail à utiliser" |
||||
|
|
||||
|
#. module: pos_mail_receipt |
||||
|
#: code:addons/pos_mail_receipt/models/pos_order.py:23 |
||||
|
#, python-format |
||||
|
msgid "E-mail already sent" |
||||
|
msgstr "E-mail déjà envoyé" |
||||
|
|
||||
|
#. module: pos_mail_receipt |
||||
|
#: model:ir.model.fields,field_description:pos_mail_receipt.field_pos_order__email_receipt_sent |
||||
|
msgid "Email Receipt Sent" |
||||
|
msgstr "Reçu envoyé" |
||||
|
|
||||
|
#. module: pos_mail_receipt |
||||
|
#: code:addons/pos_mail_receipt/models/pos_order.py:21 |
||||
|
#, python-format |
||||
|
msgid "Error: no order found" |
||||
|
msgstr "Erreur: pas de commande trouvée" |
||||
|
|
||||
|
#. module: pos_mail_receipt |
||||
|
#. openerp-web |
||||
|
#: code:addons/pos_mail_receipt/static/src/xml/pos.xml:19 |
||||
|
#, python-format |
||||
|
msgid "Mail" |
||||
|
msgstr "Mail" |
||||
|
|
||||
|
#. module: pos_mail_receipt |
||||
|
#. openerp-web |
||||
|
#: code:addons/pos_mail_receipt/static/src/xml/pos.xml:8 |
||||
|
#, python-format |
||||
|
msgid "Mail Receipt" |
||||
|
msgstr "Reçu" |
||||
|
|
||||
|
#. module: pos_mail_receipt |
||||
|
#: model:ir.model,name:pos_mail_receipt.model_pos_order |
||||
|
msgid "Point of Sale Orders" |
||||
|
msgstr "Commandes du point de vente" |
||||
|
|
||||
|
#. module: pos_mail_receipt |
||||
|
#: code:addons/pos_mail_receipt/models/pos_order.py:44 |
||||
|
#, python-format |
||||
|
msgid "Receipt_{}.pdf" |
||||
|
msgstr "Recu_{}.pdf" |
||||
|
|
||||
|
#. module: pos_mail_receipt |
||||
|
#. openerp-web |
||||
|
#: code:addons/pos_mail_receipt/static/src/js/screens.js:81 |
||||
|
#, python-format |
||||
|
msgid "The e-mail could not be sent" |
||||
|
msgstr "L'e-mail n'a pas pu être envoyé" |
||||
|
|
||||
|
#. module: pos_mail_receipt |
||||
|
#: model:mail.template,report_name:pos_mail_receipt.email_send_ticket |
||||
|
msgid "Ticket ${object.pos_reference}" |
||||
|
msgstr "Ticket ${object.pos_reference}" |
||||
|
|
||||
|
#. module: pos_mail_receipt |
||||
|
#: model:ir.model,name:pos_mail_receipt.model_report_pos_mail_receipt_pos_receipt_report |
||||
|
msgid "report.pos_mail_receipt.pos_receipt_report" |
||||
|
msgstr "" |
@ -0,0 +1,122 @@ |
|||||
|
# Translation of Odoo Server. |
||||
|
# This file contains the translation of the following modules: |
||||
|
# * pos_mail_receipt |
||||
|
# |
||||
|
msgid "" |
||||
|
msgstr "" |
||||
|
"Project-Id-Version: Odoo Server 12.0\n" |
||||
|
"Report-Msgid-Bugs-To: \n" |
||||
|
"POT-Creation-Date: 2019-12-17 14:32+0000\n" |
||||
|
"PO-Revision-Date: 2019-12-17 14:32+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: pos_mail_receipt |
||||
|
#: model:mail.template,subject:pos_mail_receipt.email_send_ticket |
||||
|
msgid "${object.pos_reference}" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_mail_receipt |
||||
|
#: model:mail.template,body_html:pos_mail_receipt.email_send_ticket |
||||
|
msgid "<p style=\"margin:0px 0 1rem 0;font-size:13px;font-family:"Lucida Grande", Helvetica, Verdana, Arial, sans-serif;\">\n" |
||||
|
"Your Ticket ${object.pos_reference}\n" |
||||
|
" </p>" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_mail_receipt |
||||
|
#. openerp-web |
||||
|
#: code:addons/pos_mail_receipt/static/src/xml/pos.xml:25 |
||||
|
#, python-format |
||||
|
msgid "Cancel" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_mail_receipt |
||||
|
#: code:addons/pos_mail_receipt/models/pos_order.py:25 |
||||
|
#, python-format |
||||
|
msgid "Cannot send the ticket, no email address found for the client" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_mail_receipt |
||||
|
#. openerp-web |
||||
|
#: code:addons/pos_mail_receipt/static/src/js/screens.js:82 |
||||
|
#, python-format |
||||
|
msgid "Check your internet connection and try again." |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_mail_receipt |
||||
|
#. openerp-web |
||||
|
#: code:addons/pos_mail_receipt/static/src/xml/pos.xml:22 |
||||
|
#, python-format |
||||
|
msgid "Confirm" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_mail_receipt |
||||
|
#. openerp-web |
||||
|
#: code:addons/pos_mail_receipt/static/src/js/screens.js:28 |
||||
|
#, python-format |
||||
|
msgid "E-mail address to use" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_mail_receipt |
||||
|
#: code:addons/pos_mail_receipt/models/pos_order.py:23 |
||||
|
#, python-format |
||||
|
msgid "E-mail already sent" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_mail_receipt |
||||
|
#: model:ir.model.fields,field_description:pos_mail_receipt.field_pos_order__email_receipt_sent |
||||
|
msgid "Email Receipt Sent" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_mail_receipt |
||||
|
#: code:addons/pos_mail_receipt/models/pos_order.py:21 |
||||
|
#, python-format |
||||
|
msgid "Error: no order found" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_mail_receipt |
||||
|
#. openerp-web |
||||
|
#: code:addons/pos_mail_receipt/static/src/xml/pos.xml:19 |
||||
|
#, python-format |
||||
|
msgid "Mail" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_mail_receipt |
||||
|
#. openerp-web |
||||
|
#: code:addons/pos_mail_receipt/static/src/xml/pos.xml:8 |
||||
|
#, python-format |
||||
|
msgid "Mail Receipt" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_mail_receipt |
||||
|
#: model:ir.model,name:pos_mail_receipt.model_pos_order |
||||
|
msgid "Point of Sale Orders" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_mail_receipt |
||||
|
#: code:addons/pos_mail_receipt/models/pos_order.py:44 |
||||
|
#, python-format |
||||
|
msgid "Receipt_{}.pdf" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_mail_receipt |
||||
|
#. openerp-web |
||||
|
#: code:addons/pos_mail_receipt/static/src/js/screens.js:81 |
||||
|
#, python-format |
||||
|
msgid "The e-mail could not be sent" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_mail_receipt |
||||
|
#: model:mail.template,report_name:pos_mail_receipt.email_send_ticket |
||||
|
msgid "Ticket ${object.pos_reference}" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_mail_receipt |
||||
|
#: model:ir.model,name:pos_mail_receipt.model_report_pos_mail_receipt_pos_receipt_report |
||||
|
msgid "report.pos_mail_receipt.pos_receipt_report" |
||||
|
msgstr "" |
||||
|
|
@ -0,0 +1 @@ |
|||||
|
from . import pos_order |
@ -0,0 +1,86 @@ |
|||||
|
# Copyright 2019 Coop IT Easy SCRLfs |
||||
|
# @author Pierrick Brun <pierrick.brun@akretion.com> |
||||
|
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). |
||||
|
|
||||
|
|
||||
|
import logging |
||||
|
import base64 |
||||
|
from odoo import fields, models, api, _ |
||||
|
|
||||
|
|
||||
|
_logger = logging.getLogger(__name__) |
||||
|
|
||||
|
|
||||
|
class PosOrder(models.Model): |
||||
|
_inherit = "pos.order" |
||||
|
|
||||
|
email_receipt_sent = fields.Boolean() |
||||
|
|
||||
|
@api.model |
||||
|
def send_mail_receipt( |
||||
|
self, pos_reference, email, body_from_ui, force=True |
||||
|
): |
||||
|
order = self.search([("pos_reference", "=", pos_reference)]) |
||||
|
if len(order) < 1: |
||||
|
_logger.error(_("Error: no order found")) |
||||
|
return |
||||
|
if order.email_receipt_sent: |
||||
|
_logger.info(_("E-mail already sent")) |
||||
|
return |
||||
|
if not email and not order.partner_id and not order.partner_id.email: |
||||
|
_logger.error( |
||||
|
_( |
||||
|
"Cannot send the ticket, " |
||||
|
"no email address found for the client" |
||||
|
) |
||||
|
) |
||||
|
email_values = {} |
||||
|
if email: |
||||
|
email_values["email_to"] = email |
||||
|
else: |
||||
|
email_values["email_to"] = order.partner_id.email |
||||
|
|
||||
|
receipt = ( |
||||
|
"<main><div class='article'><div class='pos'>" |
||||
|
"<div class='pos-receipt-container'>" |
||||
|
"{}</div></div></div></main>".format(body_from_ui) |
||||
|
) |
||||
|
|
||||
|
bodies, html_ids, header, footer, specific_paperformat_args = self.env[ |
||||
|
"ir.actions.report" |
||||
|
]._prepare_html(receipt) |
||||
|
base64_pdf = self.env["ir.actions.report"]._run_wkhtmltopdf( |
||||
|
bodies, |
||||
|
landscape=False, |
||||
|
specific_paperformat_args=specific_paperformat_args, |
||||
|
) |
||||
|
attachment = self.env["ir.attachment"].create( |
||||
|
{ |
||||
|
"name": pos_reference, |
||||
|
"datas_fname": _("Receipt_{}.pdf".format(pos_reference)), |
||||
|
"type": "binary", |
||||
|
"mimetype": "application/x-pdf", |
||||
|
"db_datas": base64.encodestring(base64_pdf), |
||||
|
"res_model": "pos.order", |
||||
|
"res_id": order.id, |
||||
|
} |
||||
|
) |
||||
|
email_values["attachment_ids"] = [attachment.id] |
||||
|
mail_template = self.env.ref("pos_mail_receipt.email_send_ticket") |
||||
|
mail_template.send_mail( |
||||
|
order.id, force_send=force, email_values=email_values, |
||||
|
) |
||||
|
order.email_receipt_sent = True |
||||
|
|
||||
|
@api.model |
||||
|
def create_from_ui(self, orders): |
||||
|
res = super(PosOrder, self).create_from_ui(orders) |
||||
|
for order in orders: |
||||
|
if "email" in order["data"]: |
||||
|
self.send_mail_receipt( |
||||
|
order["data"]["name"], |
||||
|
order["data"]["email"], |
||||
|
order["data"]["body_from_ui"], |
||||
|
force=False, |
||||
|
) |
||||
|
return res |
@ -0,0 +1,3 @@ |
|||||
|
* `Coop IT Easy SCRLfs <https://coopiteasy.be>`_: |
||||
|
|
||||
|
* Pierrick Brun |
@ -0,0 +1,5 @@ |
|||||
|
This modules allows you to send the PoS receipt by e-mail. |
||||
|
|
||||
|
Instead of printing the ticket you can choose to send it be e-mail. |
||||
|
If you know the customer's e-mail, it will use it. |
||||
|
If not you will be prompted for it. |
@ -0,0 +1,3 @@ |
|||||
|
#. Open a new PoS session. |
||||
|
#. Make an order and validate it. |
||||
|
#. You should see the company logo in the receipt preview. |
After Width: 128 | Height: 128 | Size: 9.3 KiB |
@ -0,0 +1,434 @@ |
|||||
|
<?xml version="1.0" encoding="utf-8" ?> |
||||
|
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> |
||||
|
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> |
||||
|
<head> |
||||
|
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> |
||||
|
<meta name="generator" content="Docutils 0.15.1: http://docutils.sourceforge.net/" /> |
||||
|
<title>Pos Mail Receipt</title> |
||||
|
<style type="text/css"> |
||||
|
|
||||
|
/* |
||||
|
:Author: David Goodger (goodger@python.org) |
||||
|
:Id: $Id: html4css1.css 7952 2016-07-26 18:15:59Z milde $ |
||||
|
:Copyright: This stylesheet has been placed in the public domain. |
||||
|
|
||||
|
Default cascading style sheet for the HTML output of Docutils. |
||||
|
|
||||
|
See http://docutils.sf.net/docs/howto/html-stylesheets.html for how to |
||||
|
customize this style sheet. |
||||
|
*/ |
||||
|
|
||||
|
/* used to remove borders from tables and images */ |
||||
|
.borderless, table.borderless td, table.borderless th { |
||||
|
border: 0 } |
||||
|
|
||||
|
table.borderless td, table.borderless th { |
||||
|
/* Override padding for "table.docutils td" with "! important". |
||||
|
The right padding separates the table cells. */ |
||||
|
padding: 0 0.5em 0 0 ! important } |
||||
|
|
||||
|
.first { |
||||
|
/* Override more specific margin styles with "! important". */ |
||||
|
margin-top: 0 ! important } |
||||
|
|
||||
|
.last, .with-subtitle { |
||||
|
margin-bottom: 0 ! important } |
||||
|
|
||||
|
.hidden { |
||||
|
display: none } |
||||
|
|
||||
|
.subscript { |
||||
|
vertical-align: sub; |
||||
|
font-size: smaller } |
||||
|
|
||||
|
.superscript { |
||||
|
vertical-align: super; |
||||
|
font-size: smaller } |
||||
|
|
||||
|
a.toc-backref { |
||||
|
text-decoration: none ; |
||||
|
color: black } |
||||
|
|
||||
|
blockquote.epigraph { |
||||
|
margin: 2em 5em ; } |
||||
|
|
||||
|
dl.docutils dd { |
||||
|
margin-bottom: 0.5em } |
||||
|
|
||||
|
object[type="image/svg+xml"], object[type="application/x-shockwave-flash"] { |
||||
|
overflow: hidden; |
||||
|
} |
||||
|
|
||||
|
/* Uncomment (and remove this text!) to get bold-faced definition list terms |
||||
|
dl.docutils dt { |
||||
|
font-weight: bold } |
||||
|
*/ |
||||
|
|
||||
|
div.abstract { |
||||
|
margin: 2em 5em } |
||||
|
|
||||
|
div.abstract p.topic-title { |
||||
|
font-weight: bold ; |
||||
|
text-align: center } |
||||
|
|
||||
|
div.admonition, div.attention, div.caution, div.danger, div.error, |
||||
|
div.hint, div.important, div.note, div.tip, div.warning { |
||||
|
margin: 2em ; |
||||
|
border: medium outset ; |
||||
|
padding: 1em } |
||||
|
|
||||
|
div.admonition p.admonition-title, div.hint p.admonition-title, |
||||
|
div.important p.admonition-title, div.note p.admonition-title, |
||||
|
div.tip p.admonition-title { |
||||
|
font-weight: bold ; |
||||
|
font-family: sans-serif } |
||||
|
|
||||
|
div.attention p.admonition-title, div.caution p.admonition-title, |
||||
|
div.danger p.admonition-title, div.error p.admonition-title, |
||||
|
div.warning p.admonition-title, .code .error { |
||||
|
color: red ; |
||||
|
font-weight: bold ; |
||||
|
font-family: sans-serif } |
||||
|
|
||||
|
/* Uncomment (and remove this text!) to get reduced vertical space in |
||||
|
compound paragraphs. |
||||
|
div.compound .compound-first, div.compound .compound-middle { |
||||
|
margin-bottom: 0.5em } |
||||
|
|
||||
|
div.compound .compound-last, div.compound .compound-middle { |
||||
|
margin-top: 0.5em } |
||||
|
*/ |
||||
|
|
||||
|
div.dedication { |
||||
|
margin: 2em 5em ; |
||||
|
text-align: center ; |
||||
|
font-style: italic } |
||||
|
|
||||
|
div.dedication p.topic-title { |
||||
|
font-weight: bold ; |
||||
|
font-style: normal } |
||||
|
|
||||
|
div.figure { |
||||
|
margin-left: 2em ; |
||||
|
margin-right: 2em } |
||||
|
|
||||
|
div.footer, div.header { |
||||
|
clear: both; |
||||
|
font-size: smaller } |
||||
|
|
||||
|
div.line-block { |
||||
|
display: block ; |
||||
|
margin-top: 1em ; |
||||
|
margin-bottom: 1em } |
||||
|
|
||||
|
div.line-block div.line-block { |
||||
|
margin-top: 0 ; |
||||
|
margin-bottom: 0 ; |
||||
|
margin-left: 1.5em } |
||||
|
|
||||
|
div.sidebar { |
||||
|
margin: 0 0 0.5em 1em ; |
||||
|
border: medium outset ; |
||||
|
padding: 1em ; |
||||
|
background-color: #ffffee ; |
||||
|
width: 40% ; |
||||
|
float: right ; |
||||
|
clear: right } |
||||
|
|
||||
|
div.sidebar p.rubric { |
||||
|
font-family: sans-serif ; |
||||
|
font-size: medium } |
||||
|
|
||||
|
div.system-messages { |
||||
|
margin: 5em } |
||||
|
|
||||
|
div.system-messages h1 { |
||||
|
color: red } |
||||
|
|
||||
|
div.system-message { |
||||
|
border: medium outset ; |
||||
|
padding: 1em } |
||||
|
|
||||
|
div.system-message p.system-message-title { |
||||
|
color: red ; |
||||
|
font-weight: bold } |
||||
|
|
||||
|
div.topic { |
||||
|
margin: 2em } |
||||
|
|
||||
|
h1.section-subtitle, h2.section-subtitle, h3.section-subtitle, |
||||
|
h4.section-subtitle, h5.section-subtitle, h6.section-subtitle { |
||||
|
margin-top: 0.4em } |
||||
|
|
||||
|
h1.title { |
||||
|
text-align: center } |
||||
|
|
||||
|
h2.subtitle { |
||||
|
text-align: center } |
||||
|
|
||||
|
hr.docutils { |
||||
|
width: 75% } |
||||
|
|
||||
|
img.align-left, .figure.align-left, object.align-left, table.align-left { |
||||
|
clear: left ; |
||||
|
float: left ; |
||||
|
margin-right: 1em } |
||||
|
|
||||
|
img.align-right, .figure.align-right, object.align-right, table.align-right { |
||||
|
clear: right ; |
||||
|
float: right ; |
||||
|
margin-left: 1em } |
||||
|
|
||||
|
img.align-center, .figure.align-center, object.align-center { |
||||
|
display: block; |
||||
|
margin-left: auto; |
||||
|
margin-right: auto; |
||||
|
} |
||||
|
|
||||
|
table.align-center { |
||||
|
margin-left: auto; |
||||
|
margin-right: auto; |
||||
|
} |
||||
|
|
||||
|
.align-left { |
||||
|
text-align: left } |
||||
|
|
||||
|
.align-center { |
||||
|
clear: both ; |
||||
|
text-align: center } |
||||
|
|
||||
|
.align-right { |
||||
|
text-align: right } |
||||
|
|
||||
|
/* reset inner alignment in figures */ |
||||
|
div.align-right { |
||||
|
text-align: inherit } |
||||
|
|
||||
|
/* div.align-center * { */ |
||||
|
/* text-align: left } */ |
||||
|
|
||||
|
.align-top { |
||||
|
vertical-align: top } |
||||
|
|
||||
|
.align-middle { |
||||
|
vertical-align: middle } |
||||
|
|
||||
|
.align-bottom { |
||||
|
vertical-align: bottom } |
||||
|
|
||||
|
ol.simple, ul.simple { |
||||
|
margin-bottom: 1em } |
||||
|
|
||||
|
ol.arabic { |
||||
|
list-style: decimal } |
||||
|
|
||||
|
ol.loweralpha { |
||||
|
list-style: lower-alpha } |
||||
|
|
||||
|
ol.upperalpha { |
||||
|
list-style: upper-alpha } |
||||
|
|
||||
|
ol.lowerroman { |
||||
|
list-style: lower-roman } |
||||
|
|
||||
|
ol.upperroman { |
||||
|
list-style: upper-roman } |
||||
|
|
||||
|
p.attribution { |
||||
|
text-align: right ; |
||||
|
margin-left: 50% } |
||||
|
|
||||
|
p.caption { |
||||
|
font-style: italic } |
||||
|
|
||||
|
p.credits { |
||||
|
font-style: italic ; |
||||
|
font-size: smaller } |
||||
|
|
||||
|
p.label { |
||||
|
white-space: nowrap } |
||||
|
|
||||
|
p.rubric { |
||||
|
font-weight: bold ; |
||||
|
font-size: larger ; |
||||
|
color: maroon ; |
||||
|
text-align: center } |
||||
|
|
||||
|
p.sidebar-title { |
||||
|
font-family: sans-serif ; |
||||
|
font-weight: bold ; |
||||
|
font-size: larger } |
||||
|
|
||||
|
p.sidebar-subtitle { |
||||
|
font-family: sans-serif ; |
||||
|
font-weight: bold } |
||||
|
|
||||
|
p.topic-title { |
||||
|
font-weight: bold } |
||||
|
|
||||
|
pre.address { |
||||
|
margin-bottom: 0 ; |
||||
|
margin-top: 0 ; |
||||
|
font: inherit } |
||||
|
|
||||
|
pre.literal-block, pre.doctest-block, pre.math, pre.code { |
||||
|
margin-left: 2em ; |
||||
|
margin-right: 2em } |
||||
|
|
||||
|
pre.code .ln { color: grey; } /* line numbers */ |
||||
|
pre.code, code { background-color: #eeeeee } |
||||
|
pre.code .comment, code .comment { color: #5C6576 } |
||||
|
pre.code .keyword, code .keyword { color: #3B0D06; font-weight: bold } |
||||
|
pre.code .literal.string, code .literal.string { color: #0C5404 } |
||||
|
pre.code .name.builtin, code .name.builtin { color: #352B84 } |
||||
|
pre.code .deleted, code .deleted { background-color: #DEB0A1} |
||||
|
pre.code .inserted, code .inserted { background-color: #A3D289} |
||||
|
|
||||
|
span.classifier { |
||||
|
font-family: sans-serif ; |
||||
|
font-style: oblique } |
||||
|
|
||||
|
span.classifier-delimiter { |
||||
|
font-family: sans-serif ; |
||||
|
font-weight: bold } |
||||
|
|
||||
|
span.interpreted { |
||||
|
font-family: sans-serif } |
||||
|
|
||||
|
span.option { |
||||
|
white-space: nowrap } |
||||
|
|
||||
|
span.pre { |
||||
|
white-space: pre } |
||||
|
|
||||
|
span.problematic { |
||||
|
color: red } |
||||
|
|
||||
|
span.section-subtitle { |
||||
|
/* font-size relative to parent (h1..h6 element) */ |
||||
|
font-size: 80% } |
||||
|
|
||||
|
table.citation { |
||||
|
border-left: solid 1px gray; |
||||
|
margin-left: 1px } |
||||
|
|
||||
|
table.docinfo { |
||||
|
margin: 2em 4em } |
||||
|
|
||||
|
table.docutils { |
||||
|
margin-top: 0.5em ; |
||||
|
margin-bottom: 0.5em } |
||||
|
|
||||
|
table.footnote { |
||||
|
border-left: solid 1px black; |
||||
|
margin-left: 1px } |
||||
|
|
||||
|
table.docutils td, table.docutils th, |
||||
|
table.docinfo td, table.docinfo th { |
||||
|
padding-left: 0.5em ; |
||||
|
padding-right: 0.5em ; |
||||
|
vertical-align: top } |
||||
|
|
||||
|
table.docutils th.field-name, table.docinfo th.docinfo-name { |
||||
|
font-weight: bold ; |
||||
|
text-align: left ; |
||||
|
white-space: nowrap ; |
||||
|
padding-left: 0 } |
||||
|
|
||||
|
/* "booktabs" style (no vertical lines) */ |
||||
|
table.docutils.booktabs { |
||||
|
border: 0px; |
||||
|
border-top: 2px solid; |
||||
|
border-bottom: 2px solid; |
||||
|
border-collapse: collapse; |
||||
|
} |
||||
|
table.docutils.booktabs * { |
||||
|
border: 0px; |
||||
|
} |
||||
|
table.docutils.booktabs th { |
||||
|
border-bottom: thin solid; |
||||
|
text-align: left; |
||||
|
} |
||||
|
|
||||
|
h1 tt.docutils, h2 tt.docutils, h3 tt.docutils, |
||||
|
h4 tt.docutils, h5 tt.docutils, h6 tt.docutils { |
||||
|
font-size: 100% } |
||||
|
|
||||
|
ul.auto-toc { |
||||
|
list-style-type: none } |
||||
|
|
||||
|
</style> |
||||
|
</head> |
||||
|
<body> |
||||
|
<div class="document" id="pos-mail-receipt"> |
||||
|
<h1 class="title">Pos Mail Receipt</h1> |
||||
|
|
||||
|
<!-- !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! |
||||
|
!! This file is generated by oca-gen-addon-readme !! |
||||
|
!! changes will be overwritten. !! |
||||
|
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! --> |
||||
|
<p><a class="reference external" href="https://odoo-community.org/page/development-status"><img alt="Beta" src="https://img.shields.io/badge/maturity-Beta-yellow.png" /></a> <a class="reference external" href="http://www.gnu.org/licenses/agpl-3.0-standalone.html"><img alt="License: AGPL-3" src="https://img.shields.io/badge/licence-AGPL--3-blue.png" /></a> <a class="reference external" href="https://github.com/OCA/pos/tree/12.0/pos_mail_receipt"><img alt="OCA/pos" src="https://img.shields.io/badge/github-OCA%2Fpos-lightgray.png?logo=github" /></a> <a class="reference external" href="https://translation.odoo-community.org/projects/pos-12-0/pos-12-0-pos_mail_receipt"><img alt="Translate me on Weblate" src="https://img.shields.io/badge/weblate-Translate%20me-F47D42.png" /></a> <a class="reference external" href="https://runbot.odoo-community.org/runbot/184/12.0"><img alt="Try me on Runbot" src="https://img.shields.io/badge/runbot-Try%20me-875A7B.png" /></a></p> |
||||
|
<p>This modules allows you to send the PoS receipt by e-mail.</p> |
||||
|
<p>Instead of printing the ticket you can choose to send it be e-mail. |
||||
|
If you know the customer’s e-mail, it will use it. |
||||
|
If not you will be prompted for it.</p> |
||||
|
<p><strong>Table of contents</strong></p> |
||||
|
<div class="contents local topic" id="contents"> |
||||
|
<ul class="simple"> |
||||
|
<li><a class="reference internal" href="#usage" id="id1">Usage</a></li> |
||||
|
<li><a class="reference internal" href="#bug-tracker" id="id2">Bug Tracker</a></li> |
||||
|
<li><a class="reference internal" href="#credits" id="id3">Credits</a><ul> |
||||
|
<li><a class="reference internal" href="#authors" id="id4">Authors</a></li> |
||||
|
<li><a class="reference internal" href="#contributors" id="id5">Contributors</a></li> |
||||
|
<li><a class="reference internal" href="#maintainers" id="id6">Maintainers</a></li> |
||||
|
</ul> |
||||
|
</li> |
||||
|
</ul> |
||||
|
</div> |
||||
|
<div class="section" id="usage"> |
||||
|
<h1><a class="toc-backref" href="#id1">Usage</a></h1> |
||||
|
<ol class="arabic simple"> |
||||
|
<li>Open a new PoS session.</li> |
||||
|
<li>Make an order and validate it.</li> |
||||
|
<li>You should see the company logo in the receipt preview.</li> |
||||
|
</ol> |
||||
|
</div> |
||||
|
<div class="section" id="bug-tracker"> |
||||
|
<h1><a class="toc-backref" href="#id2">Bug Tracker</a></h1> |
||||
|
<p>Bugs are tracked on <a class="reference external" href="https://github.com/OCA/pos/issues">GitHub Issues</a>. |
||||
|
In case of trouble, please check there if your issue has already been reported. |
||||
|
If you spotted it first, help us smashing it by providing a detailed and welcomed |
||||
|
<a class="reference external" href="https://github.com/OCA/pos/issues/new?body=module:%20pos_mail_receipt%0Aversion:%2012.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**">feedback</a>.</p> |
||||
|
<p>Do not contact contributors directly about support or help with technical issues.</p> |
||||
|
</div> |
||||
|
<div class="section" id="credits"> |
||||
|
<h1><a class="toc-backref" href="#id3">Credits</a></h1> |
||||
|
<div class="section" id="authors"> |
||||
|
<h2><a class="toc-backref" href="#id4">Authors</a></h2> |
||||
|
<ul class="simple"> |
||||
|
<li>Coop IT Easy SCRLfs</li> |
||||
|
</ul> |
||||
|
</div> |
||||
|
<div class="section" id="contributors"> |
||||
|
<h2><a class="toc-backref" href="#id5">Contributors</a></h2> |
||||
|
<ul class="simple"> |
||||
|
<li><a class="reference external" href="https://coopiteasy.be">Coop IT Easy SCRLfs</a>:<ul> |
||||
|
<li>Pierrick Brun</li> |
||||
|
</ul> |
||||
|
</li> |
||||
|
</ul> |
||||
|
</div> |
||||
|
<div class="section" id="maintainers"> |
||||
|
<h2><a class="toc-backref" href="#id6">Maintainers</a></h2> |
||||
|
<p>This module is maintained by the OCA.</p> |
||||
|
<a class="reference external image-reference" href="https://odoo-community.org"><img alt="Odoo Community Association" src="https://odoo-community.org/logo.png" /></a> |
||||
|
<p>OCA, or the Odoo Community Association, is a nonprofit organization whose |
||||
|
mission is to support the collaborative development of Odoo features and |
||||
|
promote its widespread use.</p> |
||||
|
<p>This module is part of the <a class="reference external" href="https://github.com/OCA/pos/tree/12.0/pos_mail_receipt">OCA/pos</a> project on GitHub.</p> |
||||
|
<p>You are welcome to contribute. To learn how please visit <a class="reference external" href="https://odoo-community.org/page/Contribute">https://odoo-community.org/page/Contribute</a>.</p> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
</body> |
||||
|
</html> |
@ -0,0 +1,3 @@ |
|||||
|
.pos .modal-dialog .popup-textinput input{ |
||||
|
margin-left: 10% |
||||
|
} |
@ -0,0 +1,129 @@ |
|||||
|
/* This is a copy of the pos receipt screen CSS |
||||
|
* This allows to use it in the backend */ |
||||
|
.pos .receipt-screen .centered-content .button { |
||||
|
line-height: 40px; |
||||
|
padding: 3px 13px; |
||||
|
font-size: 20px; |
||||
|
text-align: center; |
||||
|
background: rgb(230, 230, 230); |
||||
|
margin: 16px; |
||||
|
margin-bottom: 0px; |
||||
|
border-radius: 3px; |
||||
|
border: solid 1px rgb(209, 209, 209); |
||||
|
cursor: pointer; |
||||
|
} |
||||
|
|
||||
|
.pos .pos-receipt-container { |
||||
|
font-size: 0.75em; |
||||
|
text-align: center; |
||||
|
direction: ltr; |
||||
|
} |
||||
|
|
||||
|
.pos .pos-sale-ticket { |
||||
|
text-align: left; |
||||
|
width: 300px; |
||||
|
background-color: white; |
||||
|
margin: 20px; |
||||
|
padding: 15px; |
||||
|
font-size: 14px; |
||||
|
padding-bottom:30px; |
||||
|
display: inline-block; |
||||
|
font-family: "Inconsolata"; |
||||
|
border: solid 1px rgb(220,220,220); |
||||
|
border-radius: 3px; |
||||
|
overflow: hidden; |
||||
|
} |
||||
|
.pos .pos-sale-ticket pre{ |
||||
|
font-family: "Inconsolata"; |
||||
|
} |
||||
|
.pos .pos-sale-ticket .emph{ |
||||
|
font-size: 20px; |
||||
|
margin:5px; |
||||
|
} |
||||
|
.pos .pos-sale-ticket table { |
||||
|
width: 100%; |
||||
|
border: 0; |
||||
|
table-layout: fixed; |
||||
|
} |
||||
|
.pos .pos-sale-ticket table td { |
||||
|
border: 0; |
||||
|
word-wrap: break-word; |
||||
|
} |
||||
|
|
||||
|
@page { |
||||
|
margin: 0; |
||||
|
} |
||||
|
@media print { |
||||
|
* { |
||||
|
color: black !important; |
||||
|
} |
||||
|
body { |
||||
|
margin: 0; |
||||
|
color: white !important; |
||||
|
/* avoid black background if backgrounds are printed */ |
||||
|
background: initial; |
||||
|
} |
||||
|
.oe_leftbar, |
||||
|
.oe_loading, |
||||
|
.pos .pos-topheader, |
||||
|
.pos .pos-leftpane, |
||||
|
.pos .keyboard_frame, |
||||
|
.pos .receipt-screen header, |
||||
|
.pos .receipt-screen .top-content, |
||||
|
.pos .receipt-screen .centered-content .button { |
||||
|
display: none !important; |
||||
|
} |
||||
|
.pos, |
||||
|
.pos .pos-content, |
||||
|
.pos .rightpane, |
||||
|
.pos .screen, |
||||
|
.pos .window, |
||||
|
.pos .window .subwindow, |
||||
|
.pos .subwindow .subwindow-container{ |
||||
|
display: block; |
||||
|
position: static; |
||||
|
height: auto; |
||||
|
} |
||||
|
.pos{ |
||||
|
background: white !important; |
||||
|
} |
||||
|
.pos .rightpane { |
||||
|
left: 0px !important; |
||||
|
background-color: white; |
||||
|
} |
||||
|
.pos .receipt-screen { |
||||
|
text-align: left; |
||||
|
} |
||||
|
.pos .receipt-screen .centered-content{ |
||||
|
position: static; |
||||
|
border: none; |
||||
|
} |
||||
|
.pos .pos-receipt-container { |
||||
|
text-align: left; |
||||
|
} |
||||
|
.pos-actionbar { |
||||
|
display: none !important; |
||||
|
} |
||||
|
.debug-widget{ |
||||
|
display: none !important; |
||||
|
} |
||||
|
.pos *{ |
||||
|
text-shadow: none !important; |
||||
|
box-shadow: none !important; |
||||
|
background: transparent !important; |
||||
|
} |
||||
|
.pos .pos-sale-ticket{ |
||||
|
margin: 0; |
||||
|
margin-left: auto !important; |
||||
|
margin-right: auto !important; |
||||
|
border: none !important; |
||||
|
font-size: 13px !important; |
||||
|
width: 266px !important; |
||||
|
} |
||||
|
.o_debug_manager { |
||||
|
display: none !important; |
||||
|
} |
||||
|
.o_chat_window { |
||||
|
display: none !important; |
||||
|
} |
||||
|
} |
@ -0,0 +1,102 @@ |
|||||
|
/* License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl). */ |
||||
|
|
||||
|
|
||||
|
odoo.define("pos_mail_receipt.screens", function (require) { |
||||
|
"use strict"; |
||||
|
|
||||
|
var screens = require('point_of_sale.screens'); |
||||
|
var rpc = require('web.rpc'); |
||||
|
var core = require('web.core'); |
||||
|
var _t = core._t; |
||||
|
|
||||
|
var ReceiptScreenWidget = screens.ReceiptScreenWidget.include({ |
||||
|
renderElement: function() { |
||||
|
this._super(); |
||||
|
var self = this; |
||||
|
this.$('.button.email').click(function(){ |
||||
|
if (!self._locked) { |
||||
|
self.email(); |
||||
|
} |
||||
|
}); |
||||
|
}, |
||||
|
click_next: function() { |
||||
|
this._super(); |
||||
|
this.$('.button.email').removeClass("highlight"); |
||||
|
}, |
||||
|
email: function() { |
||||
|
var self = this; |
||||
|
var email = false; |
||||
|
var body_from_ui = this.$('.pos-receipt-container').html() |
||||
|
if( this.pos.get_order().get_client() && this.pos.get_order().get_client().email ) { |
||||
|
self._send_email_server(this.pos.get_order().name, {"email": this.pos.get_order().get_client().email, "body_from_ui": body_from_ui}); |
||||
|
} else { |
||||
|
this.gui.show_popup('textinput', { |
||||
|
'title':_t('E-mail address to use'), |
||||
|
'value': '', |
||||
|
'confirm': function(value) { |
||||
|
self._send_email_server(self.pos.get_order().name, {"email": value, "body_from_ui": body_from_ui}); |
||||
|
} |
||||
|
}); |
||||
|
} |
||||
|
}, |
||||
|
// ask the server to send the ticket as e-mail
|
||||
|
// available options:
|
||||
|
// - timeout: timeout for the rpc call in ms
|
||||
|
// - email: email to use instead of the partner's
|
||||
|
// returns a deferred
|
||||
|
_send_email_server: async function (order, options) { |
||||
|
var self = this; |
||||
|
options = options || {}; |
||||
|
var timeout = typeof options.timeout === 'number' ? options.timeout : 7500; |
||||
|
this.$('.button.email').addClass("highlight"); |
||||
|
while (self.pos.get("synch").state == "connecting") { |
||||
|
await sleep(1000); |
||||
|
} |
||||
|
|
||||
|
return rpc.query({ |
||||
|
model: 'pos.order', |
||||
|
method: 'send_mail_receipt', |
||||
|
args: [order, options["email"], options["body_from_ui"]], |
||||
|
}, { |
||||
|
timeout: timeout, |
||||
|
}) |
||||
|
.then(function (result) { |
||||
|
return true |
||||
|
}).fail(function (type, error){ |
||||
|
var connection_problem = true; |
||||
|
for (var i = 0; i < self.pos.db.get_orders().length; i++) { |
||||
|
if (order == self.pos.db.get_orders()[i].data.name) { |
||||
|
self.pos.db.get_orders()[i].data["email"] = options["email"] || false; |
||||
|
self.pos.db.get_orders()[i].data["body_from_ui"] = options["body_from_ui"] || false; |
||||
|
connection_problem = false; |
||||
|
} |
||||
|
} |
||||
|
if(error.code === 200 ){ |
||||
|
// Business Logic Error, not a connection problem
|
||||
|
//if warning do not need to display traceback!!
|
||||
|
if (error.data.exception_type == 'warning') { |
||||
|
delete error.data.debug; |
||||
|
} |
||||
|
|
||||
|
self.gui.show_popup('error-traceback',{ |
||||
|
'title': error.data.message, |
||||
|
'body': error.data.debug |
||||
|
}); |
||||
|
self.$('.button.email').removeClass("highlight"); |
||||
|
} |
||||
|
if(connection_problem){ |
||||
|
self.gui.show_popup('error',{ |
||||
|
'title': _t('The e-mail could not be sent'), |
||||
|
'body': _t('The e-mail could not be sent to ') + options["email"] + _t('. Check your internet connection and try again.'), |
||||
|
}); |
||||
|
self.$('.button.email').removeClass("highlight"); |
||||
|
} |
||||
|
}); |
||||
|
}, |
||||
|
}); |
||||
|
|
||||
|
}); |
||||
|
|
||||
|
function sleep(ms) { |
||||
|
return new Promise(resolve => setTimeout(resolve, ms)); |
||||
|
} |
@ -0,0 +1,13 @@ |
|||||
|
<?xml version="1.0" encoding="UTF-8"?> |
||||
|
|
||||
|
<templates id="template" xml:space="preserve"> |
||||
|
|
||||
|
<t t-extend="ReceiptScreenWidget"> |
||||
|
<t t-jquery=".button.print" t-operation="after"> |
||||
|
<div class="button email"> |
||||
|
<i class='fa fa-at'></i> Mail Receipt |
||||
|
</div> |
||||
|
</t> |
||||
|
</t> |
||||
|
|
||||
|
</templates> |
@ -0,0 +1,20 @@ |
|||||
|
<?xml version="1.0" encoding="utf-8"?> |
||||
|
|
||||
|
<odoo> |
||||
|
|
||||
|
<template id="assets" inherit_id="point_of_sale.assets"> |
||||
|
<xpath expr="."> |
||||
|
<link href="/pos_mail_receipt/static/src/css/pos.css" rel="stylesheet"/> |
||||
|
<script |
||||
|
type="text/javascript" |
||||
|
src="/pos_mail_receipt/static/src/js/screens.js"/> |
||||
|
</xpath> |
||||
|
</template> |
||||
|
|
||||
|
<template id="report_assets_pdf" inherit_id="web.report_assets_pdf"> |
||||
|
<xpath expr="."> |
||||
|
<link href="/pos_mail_receipt/static/src/css/print.css" rel="stylesheet"/> |
||||
|
</xpath> |
||||
|
</template> |
||||
|
|
||||
|
</odoo> |
@ -0,0 +1 @@ |
|||||
|
from . import test_module |
Some files were not shown because too many files changed in this diff
Write
Preview
Loading…
Cancel
Save
Reference in new issue