LaOsaCoop/Odoo16#12 migration pos_balance_multishop + pos_balance_epelsa
This commit is contained in:
parent
46ad866011
commit
7b37ed92a1
20 changed files with 1328 additions and 2 deletions
2
.gitignore
vendored
2
.gitignore
vendored
|
|
@ -56,7 +56,7 @@ coverage.xml
|
||||||
|
|
||||||
# Translations
|
# Translations
|
||||||
*.mo
|
*.mo
|
||||||
*.pot
|
#*.pot
|
||||||
|
|
||||||
# Django stuff:
|
# Django stuff:
|
||||||
*.log
|
*.log
|
||||||
|
|
|
||||||
46
pos_balance_epelsa/README.rst
Normal file
46
pos_balance_epelsa/README.rst
Normal file
|
|
@ -0,0 +1,46 @@
|
||||||
|
.. image:: https://img.shields.io/badge/licence-AGPL--3-blue.svg
|
||||||
|
:target: http://www.gnu.org/licenses/agpl-3.0-standalone.html
|
||||||
|
:alt: License: AGPL-3
|
||||||
|
|
||||||
|
===========================
|
||||||
|
POS Balace Multishop Epelsa
|
||||||
|
===========================
|
||||||
|
|
||||||
|
Update Euroscale Epelsa Balances
|
||||||
|
|
||||||
|
Installation
|
||||||
|
============
|
||||||
|
|
||||||
|
To install this module, you need to:
|
||||||
|
|
||||||
|
* pos_balance_multishop
|
||||||
|
|
||||||
|
TODO
|
||||||
|
====
|
||||||
|
|
||||||
|
* Nothing
|
||||||
|
|
||||||
|
Bug Tracker
|
||||||
|
===========
|
||||||
|
|
||||||
|
Bugs are tracked on `GitHub Issues
|
||||||
|
<https://github.com/acysos/odoo-addons/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.
|
||||||
|
|
||||||
|
Credits
|
||||||
|
=======
|
||||||
|
|
||||||
|
Contributors
|
||||||
|
------------
|
||||||
|
|
||||||
|
* Ignacio Ibeas <ignacio@acysos.com>
|
||||||
|
* Iñaki Santos <isantos@acysos.com>
|
||||||
|
|
||||||
|
|
||||||
|
Maintainer
|
||||||
|
----------
|
||||||
|
|
||||||
|
.. image:: https://acysos.com/logo.png
|
||||||
|
:alt: Acysos S.L.
|
||||||
|
:target: https://www.acysos.com
|
||||||
3
pos_balance_epelsa/__init__.py
Normal file
3
pos_balance_epelsa/__init__.py
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
# Copyright 2014 Ignacio Ibeas <ignacio@acysos.com>
|
||||||
|
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||||
|
from . import models
|
||||||
23
pos_balance_epelsa/__manifest__.py
Normal file
23
pos_balance_epelsa/__manifest__.py
Normal file
|
|
@ -0,0 +1,23 @@
|
||||||
|
# Copyright 2014 Ignacio Ibeas <ignacio@acysos.com>
|
||||||
|
# Copyright 2020 Santi Noreña <santi@criptomart.net>
|
||||||
|
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||||
|
{
|
||||||
|
"name": "Epelsa Balances",
|
||||||
|
"version": "16.0.1.0.0",
|
||||||
|
"category": "Specific Industries",
|
||||||
|
"summary": "Communication with Epelsa Balances.",
|
||||||
|
"description": """
|
||||||
|
Communication with Epelsa Balances.
|
||||||
|
Type Euroescale.
|
||||||
|
Communication Socket TCP/IP.
|
||||||
|
Protocol Ascii.
|
||||||
|
""",
|
||||||
|
"author": "Acysos S.L., Criptomart S.L.L.",
|
||||||
|
"website": "http://www.acysos.com, https://criptomart.net",
|
||||||
|
"license": "AGPL-3",
|
||||||
|
"depends": ["base", "pos_balance_multishop"],
|
||||||
|
"data": ["data/balance_data.xml"],
|
||||||
|
"demo": [],
|
||||||
|
"installable": True,
|
||||||
|
"auto_install": False,
|
||||||
|
}
|
||||||
9
pos_balance_epelsa/data/balance_data.xml
Normal file
9
pos_balance_epelsa/data/balance_data.xml
Normal file
|
|
@ -0,0 +1,9 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<odoo>
|
||||||
|
<data>
|
||||||
|
<record id="epelsa" model="balance.model">
|
||||||
|
<field name="name">Epelsa Socket</field>
|
||||||
|
<field name="code">epelsa_socket</field>
|
||||||
|
</record>
|
||||||
|
</data>
|
||||||
|
</odoo>
|
||||||
3
pos_balance_epelsa/models/__init__.py
Normal file
3
pos_balance_epelsa/models/__init__.py
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
# Copyright 2014 Ignacio Ibeas <ignacio@acysos.com>
|
||||||
|
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||||
|
from . import product
|
||||||
325
pos_balance_epelsa/models/product.py
Normal file
325
pos_balance_epelsa/models/product.py
Normal file
|
|
@ -0,0 +1,325 @@
|
||||||
|
# Copyright 2014 Ignacio Ibeas <ignacio@acysos.com>
|
||||||
|
# Copyright 2020 Santi Noreña - Criptomart <tech@criptomart.net>
|
||||||
|
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||||
|
|
||||||
|
import logging
|
||||||
|
import time
|
||||||
|
import socket
|
||||||
|
from unidecode import unidecode
|
||||||
|
|
||||||
|
from odoo import models, api, _
|
||||||
|
from odoo.exceptions import ValidationError, UserError
|
||||||
|
|
||||||
|
_logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
class product_balance_code(models.Model):
|
||||||
|
_inherit = "product.balance.code"
|
||||||
|
|
||||||
|
@api.onchange("key")
|
||||||
|
def _onchange_key(self):
|
||||||
|
for balance in self:
|
||||||
|
if balance.key:
|
||||||
|
if not len(balance.key) == 2:
|
||||||
|
raise ValidationError(_("The key must have 2 digits"))
|
||||||
|
if not balance.key.isdigit():
|
||||||
|
raise ValidationError(_("Key between 0-9"))
|
||||||
|
|
||||||
|
@api.onchange("table")
|
||||||
|
def _onchange_table(self):
|
||||||
|
for balance in self:
|
||||||
|
if balance.table:
|
||||||
|
if not len(balance.table) == 1:
|
||||||
|
raise ValidationError(_("The table must have 1 digit"))
|
||||||
|
if not balance.key.isdigit():
|
||||||
|
raise ValidationError(_("Table between 0-9"))
|
||||||
|
|
||||||
|
def get_checksum(self, micade):
|
||||||
|
check = 0
|
||||||
|
longitud_cade = len(micade)
|
||||||
|
i = 0
|
||||||
|
buffercheck = []
|
||||||
|
while i < longitud_cade:
|
||||||
|
buffercheck.append(micade[i : i + 1])
|
||||||
|
if buffercheck[i] == chr(126):
|
||||||
|
buffercheck[i] = chr(0)
|
||||||
|
check = check ^ ord(buffercheck[i])
|
||||||
|
i += 1
|
||||||
|
|
||||||
|
check = check ^ (longitud_cade + 2)
|
||||||
|
check = (check & 63) | 64
|
||||||
|
|
||||||
|
return check
|
||||||
|
|
||||||
|
def recv_timeout(self, the_socket, timeout=2):
|
||||||
|
# make socket non blocking
|
||||||
|
the_socket.setblocking(0)
|
||||||
|
|
||||||
|
# total data partwise in an array
|
||||||
|
total_data = []
|
||||||
|
data = ""
|
||||||
|
|
||||||
|
# beginning time
|
||||||
|
begin = time.time()
|
||||||
|
while 1:
|
||||||
|
# if you got some data, then break after timeout
|
||||||
|
if total_data and time.time() - begin > timeout:
|
||||||
|
break
|
||||||
|
|
||||||
|
# if you got no data at all, wait a little longer,
|
||||||
|
# twice the timeout
|
||||||
|
elif time.time() - begin > timeout * 2:
|
||||||
|
break
|
||||||
|
|
||||||
|
# recv something
|
||||||
|
try:
|
||||||
|
data = the_socket.recv(8192)
|
||||||
|
for ch in data:
|
||||||
|
_logger.debug(ord(ch)),
|
||||||
|
_logger.debug("\n\n")
|
||||||
|
if data:
|
||||||
|
total_data.append(data)
|
||||||
|
# change the beginning time for measurement
|
||||||
|
begin = time.time()
|
||||||
|
else:
|
||||||
|
# sleep for sometime to indicate a gap
|
||||||
|
time.sleep(0.1)
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
|
||||||
|
# join all parts to make final string
|
||||||
|
return "".join(total_data)
|
||||||
|
|
||||||
|
def add_balance_epelsa_socket(self, code, balance):
|
||||||
|
# Product
|
||||||
|
# create an INET, STREAMing socket
|
||||||
|
try:
|
||||||
|
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM, 0)
|
||||||
|
except socket.error:
|
||||||
|
_logger.debug("Failed to create socket")
|
||||||
|
return False
|
||||||
|
|
||||||
|
_logger.debug("Socket Created")
|
||||||
|
|
||||||
|
host = balance.ip
|
||||||
|
port = balance.port
|
||||||
|
|
||||||
|
try:
|
||||||
|
remote_ip = socket.gethostbyname(host)
|
||||||
|
|
||||||
|
except socket.gaierror:
|
||||||
|
# could not resolve
|
||||||
|
raise UserError(_("Error ! Hostname could not be resolved. Exiting"))
|
||||||
|
|
||||||
|
# Connect to remote server
|
||||||
|
try:
|
||||||
|
s.connect((remote_ip, port))
|
||||||
|
except:
|
||||||
|
raise UserError(_("Error ! No route to host"))
|
||||||
|
|
||||||
|
_logger.debug("Socket Connected to " + host + " on ip " + remote_ip)
|
||||||
|
|
||||||
|
# Send some data to remote server
|
||||||
|
operation = "7"
|
||||||
|
suboperation = "0"
|
||||||
|
prod_code = code.product_id.balance_name
|
||||||
|
list_price = round(code.product_id.list_price, 2)
|
||||||
|
_logger.debug("[epelsa] list_price rounded: %s " % list_price)
|
||||||
|
price = "%07d" % (round(list_price * 100, 2))
|
||||||
|
_logger.debug("[epelsa] price to send rounded: %s " % price)
|
||||||
|
|
||||||
|
if code.product_id.not_weighed:
|
||||||
|
sale_type = "U"
|
||||||
|
else:
|
||||||
|
sale_type = "W"
|
||||||
|
|
||||||
|
name = unidecode(code.product_id.name.ljust(25))
|
||||||
|
tare = code.product_id.tare
|
||||||
|
# Epelsa supports 25 char only name
|
||||||
|
name = name[:25]
|
||||||
|
message = chr(2) + operation + suboperation + prod_code + chr(0)
|
||||||
|
message += (
|
||||||
|
"01" + chr(0) + code.product_id.balance_name[2:] + chr(0) + "000" + chr(0)
|
||||||
|
)
|
||||||
|
message += "0000" + chr(0) + price + chr(0) + sale_type + chr(0)
|
||||||
|
message += "000" + chr(0) + "0" + chr(0) + name + chr(0)
|
||||||
|
message += str(tare).rjust(5, "0") + chr(0) + chr(3)
|
||||||
|
|
||||||
|
_logger.debug("Message set product: " + message)
|
||||||
|
checksum = self.get_checksum(message)
|
||||||
|
_logger.debug("Checksum: chr(" + str(checksum) + ") = " + chr(checksum))
|
||||||
|
message += chr(checksum) + chr(13)
|
||||||
|
|
||||||
|
try:
|
||||||
|
# Set the whole string
|
||||||
|
s.sendall(bytes(message, "utf-8"))
|
||||||
|
except socket.error:
|
||||||
|
# Send failed
|
||||||
|
_logger.debug("Send failed")
|
||||||
|
raise UserError(_("Error! Send failed %s") % name)
|
||||||
|
|
||||||
|
_logger.debug("Message send successfully set product : " + message)
|
||||||
|
|
||||||
|
# get reply and print
|
||||||
|
# _logger.debug('Reply set product : ' + self.recv_timeout(s))
|
||||||
|
|
||||||
|
# Close the socket
|
||||||
|
s.close()
|
||||||
|
|
||||||
|
# Key
|
||||||
|
# create an INET, STREAMing socket
|
||||||
|
try:
|
||||||
|
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM, 0)
|
||||||
|
except socket.error:
|
||||||
|
raise UserError(_("Error! Failed to create socket %s") % name)
|
||||||
|
|
||||||
|
_logger.debug("Socket Created")
|
||||||
|
|
||||||
|
try:
|
||||||
|
remote_ip = socket.gethostbyname(host)
|
||||||
|
except socket.gaierror:
|
||||||
|
# could not resolve
|
||||||
|
raise UserError(
|
||||||
|
_("Error! Hostname could not be resolved. Exiting %s") % name
|
||||||
|
)
|
||||||
|
|
||||||
|
# Connect to remote server
|
||||||
|
s.connect((remote_ip, port))
|
||||||
|
|
||||||
|
_logger.debug("Socket Connected to " + host + " on ip " + remote_ip)
|
||||||
|
|
||||||
|
# default values for key and table to prevent errors when not configured
|
||||||
|
key = "99"
|
||||||
|
table = "09"
|
||||||
|
# Send some data to remote server
|
||||||
|
operation = "5"
|
||||||
|
suboperation = "7"
|
||||||
|
mode = "1"
|
||||||
|
bal_code = balance.name
|
||||||
|
if code.table:
|
||||||
|
table = "0" + code.table
|
||||||
|
type_key = "1"
|
||||||
|
prod_code = code.product_id.balance_name
|
||||||
|
if code.key:
|
||||||
|
key = code.key
|
||||||
|
message = chr(2) + operation + suboperation + mode + chr(0)
|
||||||
|
message += bal_code + chr(0) + table + chr(0) + type_key + chr(0)
|
||||||
|
message += "01" + chr(0) + "0" + key + chr(0) + prod_code + chr(3)
|
||||||
|
|
||||||
|
_logger.debug("Message set key : " + message)
|
||||||
|
checksum = self.get_checksum(message)
|
||||||
|
_logger.debug("Checksum: chr(" + str(checksum) + ") = " + chr(checksum))
|
||||||
|
|
||||||
|
message += chr(checksum) + chr(13)
|
||||||
|
|
||||||
|
try:
|
||||||
|
# Set the whole string
|
||||||
|
s.sendall(bytes(message, "utf-8"))
|
||||||
|
except socket.error:
|
||||||
|
# Send failed
|
||||||
|
raise UserError(_("Error! Send failed %s") % name)
|
||||||
|
|
||||||
|
_logger.debug("Message send successfully set key : " + message)
|
||||||
|
|
||||||
|
# get reply and print
|
||||||
|
# _logger.debug('Reply set key : ' + self.recv_timeout(s))
|
||||||
|
|
||||||
|
# Close the socket
|
||||||
|
s.close()
|
||||||
|
return True
|
||||||
|
|
||||||
|
def remove_balance_epelsa_socket(self, code, balance):
|
||||||
|
name = unidecode(code.product_id.name.ljust(25))
|
||||||
|
try:
|
||||||
|
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM, 0)
|
||||||
|
except socket.error:
|
||||||
|
raise UserError(_("Error! Failed to create socket %s") % name)
|
||||||
|
|
||||||
|
_logger.debug("Socket Created")
|
||||||
|
|
||||||
|
host = balance.ip
|
||||||
|
port = balance.port
|
||||||
|
|
||||||
|
try:
|
||||||
|
remote_ip = socket.gethostbyname(host)
|
||||||
|
|
||||||
|
except socket.gaierror:
|
||||||
|
# could not resolve
|
||||||
|
raise UserError(
|
||||||
|
_("Error! Hostname could not be resolved. Exiting %s") % name
|
||||||
|
)
|
||||||
|
|
||||||
|
# Connect to remote server
|
||||||
|
try:
|
||||||
|
s.connect((remote_ip, port))
|
||||||
|
except:
|
||||||
|
raise UserError(_("Error! No route to host"))
|
||||||
|
|
||||||
|
_logger.debug("Socket Connected to " + host + " on ip " + remote_ip)
|
||||||
|
|
||||||
|
# Send some data to remote server
|
||||||
|
operation = "7"
|
||||||
|
suboperation = "2"
|
||||||
|
mode = "1"
|
||||||
|
prod_code = code.product_id.balance_name
|
||||||
|
|
||||||
|
message = chr(2) + operation + suboperation + mode + chr(0)
|
||||||
|
message += prod_code + chr(3)
|
||||||
|
|
||||||
|
_logger.debug("Message remove product : " + message)
|
||||||
|
checksum = self.get_checksum(message)
|
||||||
|
_logger.debug("Checksum: chr(" + str(checksum) + ") = " + chr(checksum))
|
||||||
|
|
||||||
|
message += chr(checksum) + chr(13)
|
||||||
|
|
||||||
|
try:
|
||||||
|
# Set the whole string
|
||||||
|
s.sendall(bytes(message, "utf-8"))
|
||||||
|
except socket.error:
|
||||||
|
# Send failed
|
||||||
|
raise UserError(_("Error! Send failed {}").format(name))
|
||||||
|
|
||||||
|
_logger.debug("Message send successfully remove product : " + message)
|
||||||
|
|
||||||
|
# get reply and print
|
||||||
|
_logger.debug("Reply remove product : " + self.recv_timeout(s))
|
||||||
|
|
||||||
|
# Close the socket
|
||||||
|
s.close()
|
||||||
|
return True
|
||||||
|
|
||||||
|
def update_balance_epelsa_socket(self, code, balance):
|
||||||
|
_logger.debug("updating balance")
|
||||||
|
return self.add_balance_epelsa_socket(code, balance)
|
||||||
|
|
||||||
|
|
||||||
|
class ProductTemplate(models.Model):
|
||||||
|
_inherit = "product.template"
|
||||||
|
|
||||||
|
@api.onchange("balance_name")
|
||||||
|
def _onchange_name(self):
|
||||||
|
for product in self:
|
||||||
|
if product.balance_name and not len(product.balance_name) == 6:
|
||||||
|
raise ValidationError(_("The code must have 6 digits"))
|
||||||
|
if product.balance_name and not product.balance_name.isdigit():
|
||||||
|
raise ValidationError(_("Code between 0-9"))
|
||||||
|
|
||||||
|
@api.constrains("tare")
|
||||||
|
def _check_tare(self):
|
||||||
|
tare = self.tare
|
||||||
|
if tare > 99999:
|
||||||
|
raise ValidationError(_("Tare must be maximum 99999"))
|
||||||
|
if tare % 5 != 0:
|
||||||
|
raise ValidationError(_("Tare must be multiple of 5"))
|
||||||
|
|
||||||
|
|
||||||
|
class ProductProduct(models.Model):
|
||||||
|
_inherit = "product.product"
|
||||||
|
|
||||||
|
@api.onchange("balance_name")
|
||||||
|
def _onchange_name(self):
|
||||||
|
for product in self:
|
||||||
|
if not len(product.balance_name) == 6:
|
||||||
|
raise ValidationError(_("The code must have 6 digits"))
|
||||||
|
if not product.balance_name.isdigit():
|
||||||
|
raise ValidationError(_("Code between 0-9"))
|
||||||
46
pos_balance_multishop/README.rst
Normal file
46
pos_balance_multishop/README.rst
Normal file
|
|
@ -0,0 +1,46 @@
|
||||||
|
.. image:: https://img.shields.io/badge/licence-AGPL--3-blue.svg
|
||||||
|
:target: http://www.gnu.org/licenses/agpl-3.0-standalone.html
|
||||||
|
:alt: License: AGPL-3
|
||||||
|
|
||||||
|
====================
|
||||||
|
POS Balace Multishop
|
||||||
|
====================
|
||||||
|
|
||||||
|
Add multiple code for balance products for each shop
|
||||||
|
|
||||||
|
Installation
|
||||||
|
============
|
||||||
|
|
||||||
|
To install this module, you need to:
|
||||||
|
|
||||||
|
* point_of_sale
|
||||||
|
|
||||||
|
TODO
|
||||||
|
====
|
||||||
|
|
||||||
|
* Migrate to new API massive update product
|
||||||
|
|
||||||
|
Bug Tracker
|
||||||
|
===========
|
||||||
|
|
||||||
|
Bugs are tracked on `GitHub Issues
|
||||||
|
<https://github.com/acysos/odoo-addons/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.
|
||||||
|
|
||||||
|
Credits
|
||||||
|
=======
|
||||||
|
|
||||||
|
Contributors
|
||||||
|
------------
|
||||||
|
|
||||||
|
* Ignacio Ibeas <ignacio@acysos.com>
|
||||||
|
* Iñaki Santos <isantos@acysos.com>
|
||||||
|
|
||||||
|
|
||||||
|
Maintainer
|
||||||
|
----------
|
||||||
|
|
||||||
|
.. image:: https://acysos.com/logo.png
|
||||||
|
:alt: Acysos S.L.
|
||||||
|
:target: https://www.acysos.com
|
||||||
3
pos_balance_multishop/__init__.py
Normal file
3
pos_balance_multishop/__init__.py
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
# Copyright 2014 Ignacio Ibeas <ignacio@acysos.com>
|
||||||
|
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||||
|
from . import models
|
||||||
24
pos_balance_multishop/__manifest__.py
Normal file
24
pos_balance_multishop/__manifest__.py
Normal file
|
|
@ -0,0 +1,24 @@
|
||||||
|
# Copyright 2014 Ignacio Ibeas <ignacio@acysos.com>
|
||||||
|
# Copyright 2020 Santi Noreña <santi@criptomart.net>
|
||||||
|
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||||
|
|
||||||
|
{
|
||||||
|
"name": "POS Balace Multishop",
|
||||||
|
"version": "16.0.1.0.0",
|
||||||
|
"category": "Point of sale",
|
||||||
|
"summary": "Add multiple code for balance products for each shop.",
|
||||||
|
"description": "Add multiple code for balance products for each shop.",
|
||||||
|
"depends": ["base", "point_of_sale"],
|
||||||
|
"author": "Acysos S.L., Criptomart S.L.L.",
|
||||||
|
"website": "http://www.acysos.com, https://criptomart.net",
|
||||||
|
"license": "AGPL-3",
|
||||||
|
"data": [
|
||||||
|
"security/ir.model.access.csv",
|
||||||
|
"views/product_view.xml",
|
||||||
|
"views/sale_view.xml",
|
||||||
|
],
|
||||||
|
"demo": [],
|
||||||
|
"test": [],
|
||||||
|
"installable": True,
|
||||||
|
"auto_install": False,
|
||||||
|
}
|
||||||
245
pos_balance_multishop/i18n/es.po
Normal file
245
pos_balance_multishop/i18n/es.po
Normal file
|
|
@ -0,0 +1,245 @@
|
||||||
|
# Translation of Odoo Server.
|
||||||
|
# This file contains the translation of the following modules:
|
||||||
|
# * pos_balance_multishop
|
||||||
|
#
|
||||||
|
msgid ""
|
||||||
|
msgstr ""
|
||||||
|
"Project-Id-Version: Odoo Server 12.0\n"
|
||||||
|
"Report-Msgid-Bugs-To: \n"
|
||||||
|
"POT-Creation-Date: 2021-12-02 10:21+0000\n"
|
||||||
|
"PO-Revision-Date: 2021-12-02 10:21+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_balance_multishop
|
||||||
|
#: model_terms:ir.ui.view,arch_db:pos_balance_multishop.product_balace_code_form_view
|
||||||
|
msgid "Balance"
|
||||||
|
msgstr "Saldo pendiente"
|
||||||
|
|
||||||
|
#. module: pos_balance_multishop
|
||||||
|
#: model:ir.model.fields,field_description:pos_balance_multishop.field_product_product__balance_code_ids
|
||||||
|
#: model:ir.model.fields,field_description:pos_balance_multishop.field_product_template__balance_code_ids
|
||||||
|
msgid "Balance Codes"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. module: pos_balance_multishop
|
||||||
|
#: model:ir.model,name:pos_balance_multishop.model_balance_model
|
||||||
|
#: model:ir.model.fields,field_description:pos_balance_multishop.field_sale_balance__model_id
|
||||||
|
msgid "Balance Model"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. module: pos_balance_multishop
|
||||||
|
#: model:ir.model,name:pos_balance_multishop.model_balance_sale_shop
|
||||||
|
msgid "Balance Sale Shop"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. module: pos_balance_multishop
|
||||||
|
#: model:ir.model.fields,field_description:pos_balance_multishop.field_balance_sale_shop__balance_ids
|
||||||
|
#: model_terms:ir.ui.view,arch_db:pos_balance_multishop.sale_balance_form_view
|
||||||
|
#: model_terms:ir.ui.view,arch_db:pos_balance_multishop.sale_balance_tree_view
|
||||||
|
#: model_terms:ir.ui.view,arch_db:pos_balance_multishop.view_shop_form_balance
|
||||||
|
msgid "Balances"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. module: pos_balance_multishop
|
||||||
|
#: model_terms:ir.actions.act_window,help:pos_balance_multishop.action_sale_tree
|
||||||
|
msgid "Click to create balance shop."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. module: pos_balance_multishop
|
||||||
|
#: model:ir.model.fields,field_description:pos_balance_multishop.field_balance_model__code
|
||||||
|
#: model:ir.model.fields,field_description:pos_balance_multishop.field_product_product__balance_name
|
||||||
|
#: model:ir.model.fields,field_description:pos_balance_multishop.field_product_template__balance_name
|
||||||
|
msgid "Code"
|
||||||
|
msgstr "Código"
|
||||||
|
|
||||||
|
#. module: pos_balance_multishop
|
||||||
|
#: model:ir.model.fields,field_description:pos_balance_multishop.field_balance_model__create_uid
|
||||||
|
#: model:ir.model.fields,field_description:pos_balance_multishop.field_balance_sale_shop__create_uid
|
||||||
|
#: model:ir.model.fields,field_description:pos_balance_multishop.field_product_balance_code__create_uid
|
||||||
|
#: model:ir.model.fields,field_description:pos_balance_multishop.field_sale_balance__create_uid
|
||||||
|
msgid "Created by"
|
||||||
|
msgstr "Creado por"
|
||||||
|
|
||||||
|
#. module: pos_balance_multishop
|
||||||
|
#: model:ir.model.fields,field_description:pos_balance_multishop.field_balance_model__create_date
|
||||||
|
#: model:ir.model.fields,field_description:pos_balance_multishop.field_balance_sale_shop__create_date
|
||||||
|
#: model:ir.model.fields,field_description:pos_balance_multishop.field_product_balance_code__create_date
|
||||||
|
#: model:ir.model.fields,field_description:pos_balance_multishop.field_sale_balance__create_date
|
||||||
|
msgid "Created on"
|
||||||
|
msgstr "Creado el"
|
||||||
|
|
||||||
|
#. module: pos_balance_multishop
|
||||||
|
#: model:ir.model.fields,field_description:pos_balance_multishop.field_balance_model__display_name
|
||||||
|
#: model:ir.model.fields,field_description:pos_balance_multishop.field_balance_sale_shop__display_name
|
||||||
|
#: model:ir.model.fields,field_description:pos_balance_multishop.field_product_balance_code__display_name
|
||||||
|
#: model:ir.model.fields,field_description:pos_balance_multishop.field_sale_balance__display_name
|
||||||
|
msgid "Display Name"
|
||||||
|
msgstr "Nombre mostrado"
|
||||||
|
|
||||||
|
#. module: pos_balance_multishop
|
||||||
|
#: model:ir.model.fields,field_description:pos_balance_multishop.field_balance_model__id
|
||||||
|
#: model:ir.model.fields,field_description:pos_balance_multishop.field_balance_sale_shop__id
|
||||||
|
#: model:ir.model.fields,field_description:pos_balance_multishop.field_product_balance_code__id
|
||||||
|
#: model:ir.model.fields,field_description:pos_balance_multishop.field_sale_balance__id
|
||||||
|
msgid "ID"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. module: pos_balance_multishop
|
||||||
|
#: model:ir.model.fields,field_description:pos_balance_multishop.field_sale_balance__ip
|
||||||
|
msgid "IP"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. module: pos_balance_multishop
|
||||||
|
#: model:ir.model.fields,field_description:pos_balance_multishop.field_product_balance_code__key
|
||||||
|
msgid "Key"
|
||||||
|
msgstr "Clave"
|
||||||
|
|
||||||
|
#. module: pos_balance_multishop
|
||||||
|
#: model:ir.model.fields,field_description:pos_balance_multishop.field_balance_model____last_update
|
||||||
|
#: model:ir.model.fields,field_description:pos_balance_multishop.field_balance_sale_shop____last_update
|
||||||
|
#: model:ir.model.fields,field_description:pos_balance_multishop.field_product_balance_code____last_update
|
||||||
|
#: model:ir.model.fields,field_description:pos_balance_multishop.field_sale_balance____last_update
|
||||||
|
msgid "Last Modified on"
|
||||||
|
msgstr "Última modificación en"
|
||||||
|
|
||||||
|
#. module: pos_balance_multishop
|
||||||
|
#: model:ir.model.fields,field_description:pos_balance_multishop.field_balance_model__write_uid
|
||||||
|
#: model:ir.model.fields,field_description:pos_balance_multishop.field_balance_sale_shop__write_uid
|
||||||
|
#: model:ir.model.fields,field_description:pos_balance_multishop.field_product_balance_code__write_uid
|
||||||
|
#: model:ir.model.fields,field_description:pos_balance_multishop.field_sale_balance__write_uid
|
||||||
|
msgid "Last Updated by"
|
||||||
|
msgstr "Última actualización por"
|
||||||
|
|
||||||
|
#. module: pos_balance_multishop
|
||||||
|
#: model:ir.model.fields,field_description:pos_balance_multishop.field_balance_model__write_date
|
||||||
|
#: model:ir.model.fields,field_description:pos_balance_multishop.field_balance_sale_shop__write_date
|
||||||
|
#: model:ir.model.fields,field_description:pos_balance_multishop.field_product_balance_code__write_date
|
||||||
|
#: model:ir.model.fields,field_description:pos_balance_multishop.field_sale_balance__write_date
|
||||||
|
msgid "Last Updated on"
|
||||||
|
msgstr "Última actualización el"
|
||||||
|
|
||||||
|
#. module: pos_balance_multishop
|
||||||
|
#: model:ir.model.fields,field_description:pos_balance_multishop.field_balance_model__name
|
||||||
|
#: model:ir.model.fields,field_description:pos_balance_multishop.field_sale_balance__name
|
||||||
|
msgid "Name"
|
||||||
|
msgstr "Nombre"
|
||||||
|
|
||||||
|
#. module: pos_balance_multishop
|
||||||
|
#: model:ir.model.fields,field_description:pos_balance_multishop.field_sale_balance__network
|
||||||
|
msgid "Network Connection"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. module: pos_balance_multishop
|
||||||
|
#: model:ir.model.fields,field_description:pos_balance_multishop.field_product_product__balance_nomenclature
|
||||||
|
#: model:ir.model.fields,field_description:pos_balance_multishop.field_product_template__balance_nomenclature
|
||||||
|
msgid "Nomenclature"
|
||||||
|
msgstr "Denominación"
|
||||||
|
|
||||||
|
#. module: pos_balance_multishop
|
||||||
|
#: model:ir.model.fields,field_description:pos_balance_multishop.field_product_product__not_weighed
|
||||||
|
#: model:ir.model.fields,field_description:pos_balance_multishop.field_product_template__not_weighed
|
||||||
|
msgid "Not weighed"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. module: pos_balance_multishop
|
||||||
|
#: model:ir.model.fields,field_description:pos_balance_multishop.field_sale_balance__port
|
||||||
|
msgid "Port"
|
||||||
|
msgstr "Puerto"
|
||||||
|
|
||||||
|
#. module: pos_balance_multishop
|
||||||
|
#: selection:product.template,balance_type:0
|
||||||
|
msgid "Price"
|
||||||
|
msgstr "Precio"
|
||||||
|
|
||||||
|
#. module: pos_balance_multishop
|
||||||
|
#: model:ir.model,name:pos_balance_multishop.model_product_product
|
||||||
|
#: model:ir.model.fields,field_description:pos_balance_multishop.field_product_balance_code__product_id
|
||||||
|
msgid "Product"
|
||||||
|
msgstr "Producto"
|
||||||
|
|
||||||
|
#. module: pos_balance_multishop
|
||||||
|
#: model:ir.model,name:pos_balance_multishop.model_product_balance_code
|
||||||
|
msgid "Product Balance Code"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. module: pos_balance_multishop
|
||||||
|
#: model_terms:ir.ui.view,arch_db:pos_balance_multishop.product_balace_code_form_view
|
||||||
|
msgid "Product Balance Codes"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. module: pos_balance_multishop
|
||||||
|
#: model:ir.model,name:pos_balance_multishop.model_product_template
|
||||||
|
msgid "Product Template"
|
||||||
|
msgstr "Plantilla de producto"
|
||||||
|
|
||||||
|
#. module: pos_balance_multishop
|
||||||
|
#: model:ir.model.fields,field_description:pos_balance_multishop.field_product_product__balance_rule
|
||||||
|
#: model:ir.model.fields,field_description:pos_balance_multishop.field_product_template__balance_rule
|
||||||
|
msgid "Rule"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. module: pos_balance_multishop
|
||||||
|
#: model:ir.model,name:pos_balance_multishop.model_sale_balance
|
||||||
|
msgid "Sale Balance"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. module: pos_balance_multishop
|
||||||
|
#: model:ir.actions.act_window,name:pos_balance_multishop.action_sale_tree
|
||||||
|
#: model:ir.ui.menu,name:pos_balance_multishop.menu_sale_tree
|
||||||
|
msgid "Sale balance shop"
|
||||||
|
msgstr "Tienda de venta de balanza"
|
||||||
|
|
||||||
|
#. module: pos_balance_multishop
|
||||||
|
#: model_terms:ir.ui.view,arch_db:pos_balance_multishop.view_shop_form_balance
|
||||||
|
msgid "Sale_shop"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. module: pos_balance_multishop
|
||||||
|
#: model:ir.model.fields,field_description:pos_balance_multishop.field_product_balance_code__shop_id
|
||||||
|
#: model:ir.model.fields,field_description:pos_balance_multishop.field_sale_balance__shop_id
|
||||||
|
msgid "Shop"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. module: pos_balance_multishop
|
||||||
|
#: model:ir.model.fields,field_description:pos_balance_multishop.field_product_balance_code__table
|
||||||
|
msgid "Table"
|
||||||
|
msgstr "Tabla"
|
||||||
|
|
||||||
|
#. module: pos_balance_multishop
|
||||||
|
#: model:ir.model.fields,field_description:pos_balance_multishop.field_product_product__tare
|
||||||
|
#: model:ir.model.fields,field_description:pos_balance_multishop.field_product_template__tare
|
||||||
|
msgid "Tare"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. module: pos_balance_multishop
|
||||||
|
#: model:ir.model.fields,help:pos_balance_multishop.field_product_product__tare
|
||||||
|
#: model:ir.model.fields,help:pos_balance_multishop.field_product_template__tare
|
||||||
|
msgid "Tare in grams of the product. Maximum 5 digits"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. module: pos_balance_multishop
|
||||||
|
#: model:ir.model.fields,field_description:pos_balance_multishop.field_product_product__balance_type
|
||||||
|
#: model:ir.model.fields,field_description:pos_balance_multishop.field_product_template__balance_type
|
||||||
|
msgid "Type"
|
||||||
|
msgstr "Tipo"
|
||||||
|
|
||||||
|
#. module: pos_balance_multishop
|
||||||
|
#: model:ir.actions.server,name:pos_balance_multishop.action_update_balance_codes_menu
|
||||||
|
msgid "Update Balances"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. module: pos_balance_multishop
|
||||||
|
#: selection:product.template,balance_type:0
|
||||||
|
msgid "Weight"
|
||||||
|
msgstr "Peso"
|
||||||
|
|
||||||
|
#. module: pos_balance_multishop
|
||||||
|
#: model:ir.model.fields,field_description:pos_balance_multishop.field_balance_sale_shop__name
|
||||||
|
msgid "name"
|
||||||
|
msgstr "nombre"
|
||||||
|
|
||||||
245
pos_balance_multishop/i18n/pos_balance_multishop.pot
Normal file
245
pos_balance_multishop/i18n/pos_balance_multishop.pot
Normal file
|
|
@ -0,0 +1,245 @@
|
||||||
|
# Translation of Odoo Server.
|
||||||
|
# This file contains the translation of the following modules:
|
||||||
|
# * pos_balance_multishop
|
||||||
|
#
|
||||||
|
msgid ""
|
||||||
|
msgstr ""
|
||||||
|
"Project-Id-Version: Odoo Server 12.0\n"
|
||||||
|
"Report-Msgid-Bugs-To: \n"
|
||||||
|
"POT-Creation-Date: 2021-12-02 10:20+0000\n"
|
||||||
|
"PO-Revision-Date: 2021-12-02 10:20+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_balance_multishop
|
||||||
|
#: model_terms:ir.ui.view,arch_db:pos_balance_multishop.product_balace_code_form_view
|
||||||
|
msgid "Balance"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. module: pos_balance_multishop
|
||||||
|
#: model:ir.model.fields,field_description:pos_balance_multishop.field_product_product__balance_code_ids
|
||||||
|
#: model:ir.model.fields,field_description:pos_balance_multishop.field_product_template__balance_code_ids
|
||||||
|
msgid "Balance Codes"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. module: pos_balance_multishop
|
||||||
|
#: model:ir.model,name:pos_balance_multishop.model_balance_model
|
||||||
|
#: model:ir.model.fields,field_description:pos_balance_multishop.field_sale_balance__model_id
|
||||||
|
msgid "Balance Model"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. module: pos_balance_multishop
|
||||||
|
#: model:ir.model,name:pos_balance_multishop.model_balance_sale_shop
|
||||||
|
msgid "Balance Sale Shop"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. module: pos_balance_multishop
|
||||||
|
#: model:ir.model.fields,field_description:pos_balance_multishop.field_balance_sale_shop__balance_ids
|
||||||
|
#: model_terms:ir.ui.view,arch_db:pos_balance_multishop.sale_balance_form_view
|
||||||
|
#: model_terms:ir.ui.view,arch_db:pos_balance_multishop.sale_balance_tree_view
|
||||||
|
#: model_terms:ir.ui.view,arch_db:pos_balance_multishop.view_shop_form_balance
|
||||||
|
msgid "Balances"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. module: pos_balance_multishop
|
||||||
|
#: model_terms:ir.actions.act_window,help:pos_balance_multishop.action_sale_tree
|
||||||
|
msgid "Click to create balance shop."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. module: pos_balance_multishop
|
||||||
|
#: model:ir.model.fields,field_description:pos_balance_multishop.field_balance_model__code
|
||||||
|
#: model:ir.model.fields,field_description:pos_balance_multishop.field_product_product__balance_name
|
||||||
|
#: model:ir.model.fields,field_description:pos_balance_multishop.field_product_template__balance_name
|
||||||
|
msgid "Code"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. module: pos_balance_multishop
|
||||||
|
#: model:ir.model.fields,field_description:pos_balance_multishop.field_balance_model__create_uid
|
||||||
|
#: model:ir.model.fields,field_description:pos_balance_multishop.field_balance_sale_shop__create_uid
|
||||||
|
#: model:ir.model.fields,field_description:pos_balance_multishop.field_product_balance_code__create_uid
|
||||||
|
#: model:ir.model.fields,field_description:pos_balance_multishop.field_sale_balance__create_uid
|
||||||
|
msgid "Created by"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. module: pos_balance_multishop
|
||||||
|
#: model:ir.model.fields,field_description:pos_balance_multishop.field_balance_model__create_date
|
||||||
|
#: model:ir.model.fields,field_description:pos_balance_multishop.field_balance_sale_shop__create_date
|
||||||
|
#: model:ir.model.fields,field_description:pos_balance_multishop.field_product_balance_code__create_date
|
||||||
|
#: model:ir.model.fields,field_description:pos_balance_multishop.field_sale_balance__create_date
|
||||||
|
msgid "Created on"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. module: pos_balance_multishop
|
||||||
|
#: model:ir.model.fields,field_description:pos_balance_multishop.field_balance_model__display_name
|
||||||
|
#: model:ir.model.fields,field_description:pos_balance_multishop.field_balance_sale_shop__display_name
|
||||||
|
#: model:ir.model.fields,field_description:pos_balance_multishop.field_product_balance_code__display_name
|
||||||
|
#: model:ir.model.fields,field_description:pos_balance_multishop.field_sale_balance__display_name
|
||||||
|
msgid "Display Name"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. module: pos_balance_multishop
|
||||||
|
#: model:ir.model.fields,field_description:pos_balance_multishop.field_balance_model__id
|
||||||
|
#: model:ir.model.fields,field_description:pos_balance_multishop.field_balance_sale_shop__id
|
||||||
|
#: model:ir.model.fields,field_description:pos_balance_multishop.field_product_balance_code__id
|
||||||
|
#: model:ir.model.fields,field_description:pos_balance_multishop.field_sale_balance__id
|
||||||
|
msgid "ID"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. module: pos_balance_multishop
|
||||||
|
#: model:ir.model.fields,field_description:pos_balance_multishop.field_sale_balance__ip
|
||||||
|
msgid "IP"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. module: pos_balance_multishop
|
||||||
|
#: model:ir.model.fields,field_description:pos_balance_multishop.field_product_balance_code__key
|
||||||
|
msgid "Key"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. module: pos_balance_multishop
|
||||||
|
#: model:ir.model.fields,field_description:pos_balance_multishop.field_balance_model____last_update
|
||||||
|
#: model:ir.model.fields,field_description:pos_balance_multishop.field_balance_sale_shop____last_update
|
||||||
|
#: model:ir.model.fields,field_description:pos_balance_multishop.field_product_balance_code____last_update
|
||||||
|
#: model:ir.model.fields,field_description:pos_balance_multishop.field_sale_balance____last_update
|
||||||
|
msgid "Last Modified on"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. module: pos_balance_multishop
|
||||||
|
#: model:ir.model.fields,field_description:pos_balance_multishop.field_balance_model__write_uid
|
||||||
|
#: model:ir.model.fields,field_description:pos_balance_multishop.field_balance_sale_shop__write_uid
|
||||||
|
#: model:ir.model.fields,field_description:pos_balance_multishop.field_product_balance_code__write_uid
|
||||||
|
#: model:ir.model.fields,field_description:pos_balance_multishop.field_sale_balance__write_uid
|
||||||
|
msgid "Last Updated by"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. module: pos_balance_multishop
|
||||||
|
#: model:ir.model.fields,field_description:pos_balance_multishop.field_balance_model__write_date
|
||||||
|
#: model:ir.model.fields,field_description:pos_balance_multishop.field_balance_sale_shop__write_date
|
||||||
|
#: model:ir.model.fields,field_description:pos_balance_multishop.field_product_balance_code__write_date
|
||||||
|
#: model:ir.model.fields,field_description:pos_balance_multishop.field_sale_balance__write_date
|
||||||
|
msgid "Last Updated on"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. module: pos_balance_multishop
|
||||||
|
#: model:ir.model.fields,field_description:pos_balance_multishop.field_balance_model__name
|
||||||
|
#: model:ir.model.fields,field_description:pos_balance_multishop.field_sale_balance__name
|
||||||
|
msgid "Name"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. module: pos_balance_multishop
|
||||||
|
#: model:ir.model.fields,field_description:pos_balance_multishop.field_sale_balance__network
|
||||||
|
msgid "Network Connection"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. module: pos_balance_multishop
|
||||||
|
#: model:ir.model.fields,field_description:pos_balance_multishop.field_product_product__balance_nomenclature
|
||||||
|
#: model:ir.model.fields,field_description:pos_balance_multishop.field_product_template__balance_nomenclature
|
||||||
|
msgid "Nomenclature"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. module: pos_balance_multishop
|
||||||
|
#: model:ir.model.fields,field_description:pos_balance_multishop.field_product_product__not_weighed
|
||||||
|
#: model:ir.model.fields,field_description:pos_balance_multishop.field_product_template__not_weighed
|
||||||
|
msgid "Not weighed"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. module: pos_balance_multishop
|
||||||
|
#: model:ir.model.fields,field_description:pos_balance_multishop.field_sale_balance__port
|
||||||
|
msgid "Port"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. module: pos_balance_multishop
|
||||||
|
#: selection:product.template,balance_type:0
|
||||||
|
msgid "Price"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. module: pos_balance_multishop
|
||||||
|
#: model:ir.model,name:pos_balance_multishop.model_product_product
|
||||||
|
#: model:ir.model.fields,field_description:pos_balance_multishop.field_product_balance_code__product_id
|
||||||
|
msgid "Product"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. module: pos_balance_multishop
|
||||||
|
#: model:ir.model,name:pos_balance_multishop.model_product_balance_code
|
||||||
|
msgid "Product Balance Code"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. module: pos_balance_multishop
|
||||||
|
#: model_terms:ir.ui.view,arch_db:pos_balance_multishop.product_balace_code_form_view
|
||||||
|
msgid "Product Balance Codes"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. module: pos_balance_multishop
|
||||||
|
#: model:ir.model,name:pos_balance_multishop.model_product_template
|
||||||
|
msgid "Product Template"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. module: pos_balance_multishop
|
||||||
|
#: model:ir.model.fields,field_description:pos_balance_multishop.field_product_product__balance_rule
|
||||||
|
#: model:ir.model.fields,field_description:pos_balance_multishop.field_product_template__balance_rule
|
||||||
|
msgid "Rule"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. module: pos_balance_multishop
|
||||||
|
#: model:ir.model,name:pos_balance_multishop.model_sale_balance
|
||||||
|
msgid "Sale Balance"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. module: pos_balance_multishop
|
||||||
|
#: model:ir.actions.act_window,name:pos_balance_multishop.action_sale_tree
|
||||||
|
#: model:ir.ui.menu,name:pos_balance_multishop.menu_sale_tree
|
||||||
|
msgid "Sale balance shop"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. module: pos_balance_multishop
|
||||||
|
#: model_terms:ir.ui.view,arch_db:pos_balance_multishop.view_shop_form_balance
|
||||||
|
msgid "Sale_shop"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. module: pos_balance_multishop
|
||||||
|
#: model:ir.model.fields,field_description:pos_balance_multishop.field_product_balance_code__shop_id
|
||||||
|
#: model:ir.model.fields,field_description:pos_balance_multishop.field_sale_balance__shop_id
|
||||||
|
msgid "Shop"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. module: pos_balance_multishop
|
||||||
|
#: model:ir.model.fields,field_description:pos_balance_multishop.field_product_balance_code__table
|
||||||
|
msgid "Table"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. module: pos_balance_multishop
|
||||||
|
#: model:ir.model.fields,field_description:pos_balance_multishop.field_product_product__tare
|
||||||
|
#: model:ir.model.fields,field_description:pos_balance_multishop.field_product_template__tare
|
||||||
|
msgid "Tare"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. module: pos_balance_multishop
|
||||||
|
#: model:ir.model.fields,help:pos_balance_multishop.field_product_product__tare
|
||||||
|
#: model:ir.model.fields,help:pos_balance_multishop.field_product_template__tare
|
||||||
|
msgid "Tare in grams of the product. Maximum 5 digits"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. module: pos_balance_multishop
|
||||||
|
#: model:ir.model.fields,field_description:pos_balance_multishop.field_product_product__balance_type
|
||||||
|
#: model:ir.model.fields,field_description:pos_balance_multishop.field_product_template__balance_type
|
||||||
|
msgid "Type"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. module: pos_balance_multishop
|
||||||
|
#: model:ir.actions.server,name:pos_balance_multishop.action_update_balance_codes_menu
|
||||||
|
msgid "Update Balances"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. module: pos_balance_multishop
|
||||||
|
#: selection:product.template,balance_type:0
|
||||||
|
msgid "Weight"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. module: pos_balance_multishop
|
||||||
|
#: model:ir.model.fields,field_description:pos_balance_multishop.field_balance_sale_shop__name
|
||||||
|
msgid "name"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
25
pos_balance_multishop/models/__init__.py
Normal file
25
pos_balance_multishop/models/__init__.py
Normal file
|
|
@ -0,0 +1,25 @@
|
||||||
|
########################################################################
|
||||||
|
#
|
||||||
|
# @authors: Ignacio Ibeas <ignacio@acysos.com>
|
||||||
|
# Copyright (C) 2014 Acysos S.L.
|
||||||
|
#
|
||||||
|
#This program is free software: you can redistribute it and/or modify
|
||||||
|
#it under the terms of the GNU General Public License as published by
|
||||||
|
#the Free Software Foundation, either version 3 of the License, or
|
||||||
|
#(at your option) any later version.
|
||||||
|
#
|
||||||
|
# This module is GPLv3 or newer and incompatible
|
||||||
|
# with OpenERP SA "AGPL + Private Use License"!
|
||||||
|
#
|
||||||
|
#This program is distributed in the hope that it will be useful,
|
||||||
|
#but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
#MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
#GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
#You should have received a copy of the GNU General Public License
|
||||||
|
#along with this program. If not, see http://www.gnu.org/licenses.
|
||||||
|
########################################################################
|
||||||
|
|
||||||
|
from . import product
|
||||||
|
from . import sale_balance
|
||||||
|
from . import sale
|
||||||
151
pos_balance_multishop/models/product.py
Normal file
151
pos_balance_multishop/models/product.py
Normal file
|
|
@ -0,0 +1,151 @@
|
||||||
|
# Copyright 2014 Ignacio Ibeas <ignacio@acysos.com>
|
||||||
|
# Copyright 2020 Santi Noreña <santi@criptomart.net>
|
||||||
|
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||||
|
|
||||||
|
import logging
|
||||||
|
|
||||||
|
from odoo import api, models, fields, _
|
||||||
|
|
||||||
|
_logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
class ProductTemplate(models.Model):
|
||||||
|
_inherit = "product.template"
|
||||||
|
|
||||||
|
balance_code_ids = fields.One2many(
|
||||||
|
comodel_name="product.balance.code",
|
||||||
|
inverse_name="product_id",
|
||||||
|
string="Balance Codes",
|
||||||
|
)
|
||||||
|
balance_type = fields.Selection(
|
||||||
|
[("price", "Price"), ("weight", "Weight")], "Type Balance"
|
||||||
|
)
|
||||||
|
balance_name = fields.Char(string="Code", readonly=False, related="default_code")
|
||||||
|
balance_nomenclature = fields.Many2one(
|
||||||
|
comodel_name="barcode.nomenclature", string="Nomenclature"
|
||||||
|
)
|
||||||
|
balance_rule = fields.Many2one(comodel_name="barcode.rule", string="Rule")
|
||||||
|
not_weighed = fields.Boolean("Not weighed", required=False)
|
||||||
|
|
||||||
|
tare = fields.Integer(
|
||||||
|
string="Tare",
|
||||||
|
help="Tare in grams of the product. Maximum 5 digits",
|
||||||
|
default=0,
|
||||||
|
readonly=False,
|
||||||
|
)
|
||||||
|
|
||||||
|
@api.onchange("balance_name", "balance_rule")
|
||||||
|
def get_ean_code(self):
|
||||||
|
barcode = False
|
||||||
|
for product in self:
|
||||||
|
if self.balance_rule and self.balance_name:
|
||||||
|
ean = product.balance_rule.pattern[:1]
|
||||||
|
ean += product.balance_name
|
||||||
|
ean += "00000"
|
||||||
|
code = list(ean)
|
||||||
|
oddsum = evensum = total = control_digit = 0
|
||||||
|
for i in range(len(code)):
|
||||||
|
if i % 2 == 0:
|
||||||
|
# even calculation
|
||||||
|
evensum += int(code[i])
|
||||||
|
else:
|
||||||
|
# odd calculation
|
||||||
|
oddsum += int(code[i])
|
||||||
|
total = oddsum * 3 + evensum
|
||||||
|
control_digit = int((10 - total % 10) % 10)
|
||||||
|
barcode = ean + str(control_digit)
|
||||||
|
product.barcode = barcode
|
||||||
|
|
||||||
|
def update_codes(self):
|
||||||
|
# _logger.debug("updating codes")
|
||||||
|
for product in self:
|
||||||
|
if len(product.balance_code_ids) > 0:
|
||||||
|
for code in product.balance_code_ids:
|
||||||
|
if len(code.shop_id.balance_ids) > 0:
|
||||||
|
code.remove_balance()
|
||||||
|
code.update_balance()
|
||||||
|
|
||||||
|
|
||||||
|
class product_balance_code(models.Model):
|
||||||
|
_name = "product.balance.code"
|
||||||
|
_description = "Product Balance Code"
|
||||||
|
|
||||||
|
def add_balance(self):
|
||||||
|
for code in self:
|
||||||
|
for balance in code.shop_id.balance_ids:
|
||||||
|
if balance.network:
|
||||||
|
balance_con = getattr(self, "add_balance_" + balance.model_id.code)
|
||||||
|
balance_con(code, balance)
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
|
def update_balance(self):
|
||||||
|
for code in self:
|
||||||
|
# _logger.debug("code : " + code )
|
||||||
|
for balance in code.shop_id.balance_ids:
|
||||||
|
_logger.debug("balance con ")
|
||||||
|
if balance.network:
|
||||||
|
# _logger.debug("balance con " + balance)
|
||||||
|
balance_con = getattr(
|
||||||
|
self, "update_balance_" + balance.model_id.code
|
||||||
|
)
|
||||||
|
# _logger.debug('update_balance_' + balance.model_id.code))
|
||||||
|
balance_con(code, balance)
|
||||||
|
return True
|
||||||
|
|
||||||
|
def remove_balance(self):
|
||||||
|
for code in self:
|
||||||
|
for balance in code.shop_id.balance_ids:
|
||||||
|
if balance.network:
|
||||||
|
balance_con = getattr(
|
||||||
|
self, "remove_balance_" + balance.model_id.code
|
||||||
|
)
|
||||||
|
balance_con(code, balance)
|
||||||
|
return True
|
||||||
|
|
||||||
|
product_id = fields.Many2one(
|
||||||
|
comodel_name="product.template", string="Product", required=True
|
||||||
|
)
|
||||||
|
key = fields.Char(string="Key")
|
||||||
|
table = fields.Char(string="Table")
|
||||||
|
shop_id = fields.Many2one(comodel_name="balance.sale.shop", string="Shop")
|
||||||
|
|
||||||
|
|
||||||
|
class ProductProduct(models.Model):
|
||||||
|
_inherit = "product.product"
|
||||||
|
|
||||||
|
@api.onchange("balance_name", "balance_rule")
|
||||||
|
def get_ean_code(self):
|
||||||
|
barcode = False
|
||||||
|
for product in self:
|
||||||
|
if self.balance_rule and self.balance_name:
|
||||||
|
ean = product.balance_rule.pattern[:1]
|
||||||
|
ean += product.balance_name
|
||||||
|
ean += "00000"
|
||||||
|
code = list(ean)
|
||||||
|
|
||||||
|
oddsum = evensum = total = control_digit = 0
|
||||||
|
for i in range(len(code)):
|
||||||
|
if i % 2 == 0:
|
||||||
|
# even calculation
|
||||||
|
evensum += int(code[i])
|
||||||
|
else:
|
||||||
|
# odd calculation
|
||||||
|
oddsum += int(code[i])
|
||||||
|
total = oddsum * 3 + evensum
|
||||||
|
|
||||||
|
control_digit = int((10 - total % 10) % 10)
|
||||||
|
barcode = ean + str(control_digit)
|
||||||
|
product.barcode = barcode
|
||||||
|
|
||||||
|
def unlink(self):
|
||||||
|
self.balance_code_ids.remove_balance()
|
||||||
|
res = super(ProductProduct, self).unlink()
|
||||||
|
return res
|
||||||
|
|
||||||
|
def update_codes(self):
|
||||||
|
for product in self:
|
||||||
|
if len(product.balance_code_ids) > 0:
|
||||||
|
for code in product.balance_code_ids:
|
||||||
|
if len(code.shop_id.balance_ids) > 0:
|
||||||
|
code.remove_balance()
|
||||||
14
pos_balance_multishop/models/sale.py
Normal file
14
pos_balance_multishop/models/sale.py
Normal file
|
|
@ -0,0 +1,14 @@
|
||||||
|
# Copyright 2014 Ignacio Ibeas <ignacio@acysos.com>
|
||||||
|
# Copyright 2020 Santi Noreña <santi@criptomart.net>
|
||||||
|
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||||
|
from odoo import models, fields, _
|
||||||
|
|
||||||
|
|
||||||
|
class balance_sale_shop(models.Model):
|
||||||
|
_name = "balance.sale.shop"
|
||||||
|
_description = "Balance Sale Shop"
|
||||||
|
|
||||||
|
name = fields.Char("Name")
|
||||||
|
balance_ids = fields.One2many(
|
||||||
|
comodel_name="sale.balance", inverse_name="shop_id", string="Balances"
|
||||||
|
)
|
||||||
27
pos_balance_multishop/models/sale_balance.py
Normal file
27
pos_balance_multishop/models/sale_balance.py
Normal file
|
|
@ -0,0 +1,27 @@
|
||||||
|
# Copyright 2014 Ignacio Ibeas <ignacio@acysos.com>
|
||||||
|
# Copyright 2020 Santi Noreña <santi@criptomart.net>
|
||||||
|
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||||
|
|
||||||
|
from odoo import models, fields, _
|
||||||
|
|
||||||
|
|
||||||
|
class balance_model(models.Model):
|
||||||
|
_name = "balance.model"
|
||||||
|
_description = "Balance Model"
|
||||||
|
|
||||||
|
name = fields.Char(string="Name", required=True, readonly=True)
|
||||||
|
code = fields.Char(string="Code", required=True, readonly=True)
|
||||||
|
|
||||||
|
|
||||||
|
class sale_balance(models.Model):
|
||||||
|
_name = "sale.balance"
|
||||||
|
_description = "Sale Balance"
|
||||||
|
|
||||||
|
name = fields.Char("Name")
|
||||||
|
shop_id = fields.Many2one(comodel_name="balance.sale.shop", string="Shop")
|
||||||
|
network = fields.Boolean("Network Connection", required=False)
|
||||||
|
model_id = fields.Many2one(
|
||||||
|
comodel_name="balance.model", string="Balance Model", required=False
|
||||||
|
)
|
||||||
|
ip = fields.Char("IP", required=False, readonly=False)
|
||||||
|
port = fields.Integer("Port")
|
||||||
13
pos_balance_multishop/security/ir.model.access.csv
Normal file
13
pos_balance_multishop/security/ir.model.access.csv
Normal file
|
|
@ -0,0 +1,13 @@
|
||||||
|
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
|
||||||
|
access_product_balance_code_all,product.balance.code,model_product_balance_code,base.group_user,1,0,0,0
|
||||||
|
access_product_balance_code_user,product.balance.code,model_product_balance_code,point_of_sale.group_pos_user,1,1,1,0
|
||||||
|
access_product_balance_code_manager,product.balance.code manager,model_product_balance_code,point_of_sale.group_pos_manager,1,1,1,1
|
||||||
|
access_product_balance_shop_all,balance.sale.shop user,model_balance_sale_shop,base.group_user,1,0,0,0
|
||||||
|
access_product_balance_shop_user,balance.sale.shop user,model_balance_sale_shop,point_of_sale.group_pos_user,1,1,1,0
|
||||||
|
access_product_balance_shop_manager,balance.sale.shop manager,model_balance_sale_shop,point_of_sale.group_pos_manager,1,1,1,1
|
||||||
|
access_sale_balance_all,sale.balance user,model_sale_balance,base.group_user,1,0,0,0
|
||||||
|
access_sale_balance_user,sale.balance user,model_sale_balance,point_of_sale.group_pos_user,1,1,1,0
|
||||||
|
access_sale_balance_manager,sale.balance manager,model_sale_balance,point_of_sale.group_pos_manager,1,1,1,1
|
||||||
|
access_balance_model_all,balance.model user,model_balance_model,base.group_user,1,0,0,0
|
||||||
|
access_balance_model_user,balance.model user,model_balance_model,point_of_sale.group_pos_user,1,1,1,0
|
||||||
|
access_balance_model_manager,balance.model manager,model_balance_model,point_of_sale.group_pos_manager,1,1,1,1
|
||||||
|
53
pos_balance_multishop/views/product_view.xml
Normal file
53
pos_balance_multishop/views/product_view.xml
Normal file
|
|
@ -0,0 +1,53 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<odoo>
|
||||||
|
<data>
|
||||||
|
|
||||||
|
<record model="ir.ui.view" id="product_balace_code_form_view">
|
||||||
|
<field name="name">product.balance.code.form</field>
|
||||||
|
<field name="model">product.template</field>
|
||||||
|
<field name="type">form</field>
|
||||||
|
<field name="inherit_id" ref="product.product_template_form_view"/>
|
||||||
|
<field name="arch" type="xml">
|
||||||
|
<page name="general_information" position="after">
|
||||||
|
<page string="Balance">
|
||||||
|
<group>
|
||||||
|
<field name="balance_type"/>
|
||||||
|
<field name="balance_name"/>
|
||||||
|
<field name="balance_nomenclature"/>
|
||||||
|
<field name="balance_rule" domain="['|',('type','=','price'),('type','=','weight')]"/>
|
||||||
|
<field name="not_weighed"/>
|
||||||
|
<field name="tare"/>
|
||||||
|
</group>
|
||||||
|
<field name="balance_code_ids" nolabel="1">
|
||||||
|
<form string="Product Balance Codes">
|
||||||
|
<group>
|
||||||
|
<field name="key"/>
|
||||||
|
<field name="table"/>
|
||||||
|
<field name="shop_id"/>
|
||||||
|
</group>
|
||||||
|
</form>
|
||||||
|
<tree string="Product Balance Codes" editable="top">
|
||||||
|
<field name="key"/>
|
||||||
|
<field name="table"/>
|
||||||
|
<field name="shop_id" />
|
||||||
|
</tree>
|
||||||
|
</field>
|
||||||
|
</page>
|
||||||
|
</page>
|
||||||
|
</field>
|
||||||
|
</record>
|
||||||
|
|
||||||
|
<record id="action_update_balance_codes_menu" model="ir.actions.server">
|
||||||
|
<field name="name">Update Balances</field>
|
||||||
|
<field name="type">ir.actions.server</field>
|
||||||
|
<field name="model_id" ref="product.model_product_template" />
|
||||||
|
<field name="binding_model_id" ref="product.model_product_template"/>
|
||||||
|
<field name="state">code</field>
|
||||||
|
<field name="code">
|
||||||
|
if records:
|
||||||
|
records.update_codes()
|
||||||
|
</field>
|
||||||
|
</record>
|
||||||
|
|
||||||
|
</data>
|
||||||
|
</odoo>
|
||||||
71
pos_balance_multishop/views/sale_view.xml
Normal file
71
pos_balance_multishop/views/sale_view.xml
Normal file
|
|
@ -0,0 +1,71 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<odoo>
|
||||||
|
<data>
|
||||||
|
<record model="ir.ui.view" id="view_shop_form_balance">
|
||||||
|
<field name="name">balance.sale.shop.form</field>
|
||||||
|
<field name="model">balance.sale.shop</field>
|
||||||
|
<field name="type">form</field>
|
||||||
|
<field name="arch" type="xml">
|
||||||
|
<sheet string="Sale_shop">
|
||||||
|
<group>
|
||||||
|
<field name="name"/>
|
||||||
|
<field name="balance_ids" />
|
||||||
|
</group>
|
||||||
|
</sheet>
|
||||||
|
</field>
|
||||||
|
</record>
|
||||||
|
|
||||||
|
<record model="ir.ui.view" id="sale_balance_form_view">
|
||||||
|
<field name="name">sale.balance.form</field>
|
||||||
|
<field name="model">sale.balance</field>
|
||||||
|
<field name="type">form</field>
|
||||||
|
<field name="arch" type="xml">
|
||||||
|
<group>
|
||||||
|
<form string="Balances">
|
||||||
|
<group>
|
||||||
|
<field name="name" />
|
||||||
|
<field name="shop_id"/>
|
||||||
|
<field name="network" />
|
||||||
|
<field name="model_id" />
|
||||||
|
<field name="ip" />
|
||||||
|
<field name="port" />
|
||||||
|
</group>
|
||||||
|
</form>
|
||||||
|
</group>
|
||||||
|
</field>
|
||||||
|
</record>
|
||||||
|
|
||||||
|
<record model="ir.ui.view" id="sale_balance_tree_view">
|
||||||
|
<field name="name">sale.balance.form</field>
|
||||||
|
<field name="model">sale.balance</field>
|
||||||
|
<field name="type">tree</field>
|
||||||
|
<field name="arch" type="xml">
|
||||||
|
<tree string="Balances" editable="top">
|
||||||
|
<field name="name" />
|
||||||
|
<field name="network" />
|
||||||
|
<field name="model_id" />
|
||||||
|
<field name="ip" />
|
||||||
|
<field name="port" />
|
||||||
|
</tree>
|
||||||
|
</field>
|
||||||
|
</record>
|
||||||
|
|
||||||
|
<record id="action_sale_tree" model="ir.actions.act_window">
|
||||||
|
<field name="name">Sale balance shop</field>
|
||||||
|
<field name="type">ir.actions.act_window</field>
|
||||||
|
<field name="res_model">balance.sale.shop</field>
|
||||||
|
<field name="view_mode">tree,form</field>
|
||||||
|
<field name="view_id" eval="False"/>
|
||||||
|
<field name="help" type="html">
|
||||||
|
<p class="oe_view_nocontent_create">
|
||||||
|
Click to create balance shop.
|
||||||
|
</p>
|
||||||
|
</field>
|
||||||
|
</record>
|
||||||
|
|
||||||
|
<menuitem action="action_sale_tree" id="menu_sale_tree"
|
||||||
|
parent="point_of_sale.menu_point_config_product" sequence="1"
|
||||||
|
/>
|
||||||
|
|
||||||
|
</data>
|
||||||
|
</odoo>
|
||||||
|
|
@ -14,7 +14,7 @@ class ProductTemplate(models.Model):
|
||||||
string="Last purchase price",
|
string="Last purchase price",
|
||||||
help="The last price at which the product was purchased. "
|
help="The last price at which the product was purchased. "
|
||||||
"It is used as the base price field for calculating the product sale price.",
|
"It is used as the base price field for calculating the product sale price.",
|
||||||
readonly=True,
|
# readonly=True,
|
||||||
digits="Product Price",
|
digits="Product Price",
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue