Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
T
third-party
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
2
Merge Requests
2
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
cooperatic-foodcoops
third-party
Commits
2825333f
Commit
2825333f
authored
Apr 14, 2022
by
Damien Moulard
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
ALC: update products stock & price
parent
01c46ba9
Hide whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
164 additions
and
53 deletions
+164
-53
models.py
inventory/models.py
+2
-2
oders_helper_style.css
orders/static/css/oders_helper_style.css
+34
-2
orders_helper.js
orders/static/js/orders_helper.js
+31
-8
models.py
products/models.py
+21
-8
views.py
products/views.py
+33
-14
helper.html
templates/orders/helper.html
+43
-19
No files found.
inventory/models.py
View file @
2825333f
...
...
@@ -368,10 +368,10 @@ class CagetteInventory(models.Model):
return
{
'missed'
:
missed
,
'unchanged'
:
unchanged
,
'done'
:
done
}
@staticmethod
def
update_products_stock
(
inventory_data
):
def
update_products_stock
(
inventory_data
,
precision
=
2
):
""" Updates Odoo stock after a shelf inventory or another action"""
TWOPLACES
=
Decimal
(
10
)
**
-
2
TWOPLACES
=
Decimal
(
10
)
**
-
precision
api
=
OdooAPI
()
missed
=
[]
unchanged
=
[]
...
...
orders/static/css/oders_helper_style.css
View file @
2825333f
...
...
@@ -381,14 +381,46 @@
display
:
block
;
}
.modal_product_actions_section
{
.product_actions_container
{
display
:
flex
;
flex-direction
:
column
;
}
.product_actions_section
{
width
:
100%
;
display
:
flex
;
margin
:
1em
0
;
}
.modal_product_actions_section
.tooltip
{
.product_actions_column
{
width
:
50%
;
}
.product_actions_full_column
{
width
:
100%
;
}
.product_actions_column
.tooltip
{
margin-left
:
5px
;
}
.product_prices_title
{
margin-bottom
:
0
!important
;
}
.product_prices_area
{
margin
:
20px
0
;
display
:
flex
;
flex-direction
:
column
;
gap
:
10px
;
}
.product_price_action
{
display
:
flex
;
justify-content
:
center
;
align-items
:
center
;
gap
:
10px
;
}
.modal_product_actions_title
{
font-weight
:
bold
;
font-size
:
2.2rem
;
...
...
orders/static/js/orders_helper.js
View file @
2825333f
...
...
@@ -30,12 +30,9 @@ var dbc = null,
fingerprint
=
null
;
var
clicked_order_pill
=
null
;
let
userAgent
=
navigator
.
userAgent
;
var
timerId
;
/* - UTILS */
/**
...
...
@@ -669,13 +666,14 @@ function save_supplier_product_association(product, supplier, cell) {
traditional
:
true
,
contentType
:
"application/json; charset=utf-8"
,
data
:
JSON
.
stringify
(
data
),
success
:
()
=>
{
success
:
(
res_data
)
=>
{
// Save supplierinfo in product
if
(
!
(
'suppliersinfo'
in
product
))
{
product
.
suppliersinfo
=
[];
}
product
.
suppliersinfo
.
push
({
id
:
res_data
.
res
.
psi_id
,
supplier_id
:
supplier
.
id
,
package_qty
:
package_qty
,
product_code
:
false
,
...
...
@@ -859,8 +857,10 @@ function commit_actions_on_product(product, inputs) {
npa
:
[],
to_archive
:
false
,
minimal_stock
:
0
,
qty_available
:
0
,
id
:
product
.
id
,
name
:
product
.
name
name
:
product
.
name
,
suppliersinfo
:
[]
};
inputs
.
each
(
function
(
i
,
e
)
{
...
...
@@ -876,6 +876,13 @@ function commit_actions_on_product(product, inputs) {
if
(
input
.
prop
(
'checked'
)
==
true
&&
product
.
incoming_qty
===
0
)
{
actions
.
to_archive
=
true
;
}
}
else
if
(
input
.
attr
(
'name'
)
==
"actual_stock"
)
{
actions
.
qty_available
=
parseFloat
(
input
.
val
());
}
else
if
(
input
.
attr
(
'class'
)
!==
undefined
&&
input
.
attr
(
'class'
).
includes
(
"product_supplier_price"
))
{
actions
.
suppliersinfo
.
push
({
supplierinfo_id
:
parseInt
(
input
.
attr
(
'supplierinfo_id'
)),
price
:
parseFloat
(
input
.
val
())
});
}
});
...
...
@@ -1810,11 +1817,10 @@ function display_products(params) {
const
product
=
products
.
find
(
p
=>
p
.
id
==
p_id
);
let
modal_product_actions
=
$
(
'#templates #modal_product_actions'
);
modal_product_actions
.
find
(
".product_name"
).
text
(
product
.
name
);
modal_product_actions
.
find
(
".actual_stock_input"
).
val
(
product
.
qty_available
);
const
product_can_be_archived
=
product
.
incoming_qty
===
0
;
if
(
product_can_be_archived
==
true
)
{
modal_product_actions
.
find
(
'input[name="archive-action"]'
).
prop
(
"disabled"
,
false
);
modal_product_actions
.
find
(
'input[name="archive-action"]'
).
closest
(
"label"
)
...
...
@@ -1825,6 +1831,17 @@ function display_products(params) {
.
addClass
(
"checkbox_action_disabled"
);
}
let
product_price_action_template
=
$
(
'#templates #product_price_action_template'
);
modal_product_actions
.
find
(
".product_prices_area"
).
empty
();
for
(
let
supplierinfo
of
product
.
suppliersinfo
)
{
let
supplier
=
suppliers_list
.
find
(
s
=>
s
.
id
==
supplierinfo
.
supplier_id
);
product_price_action_template
.
find
(
".supplier_name"
).
text
(
supplier
.
display_name
);
product_price_action_template
.
find
(
".product_supplier_price"
).
attr
(
'supplierinfo_id'
,
supplierinfo
.
id
);
modal_product_actions
.
find
(
".product_prices_area"
).
append
(
product_price_action_template
.
html
());
}
openModal
(
modal_product_actions
.
html
(),
()
=>
{
...
...
@@ -1835,7 +1852,13 @@ function display_products(params) {
'Valider'
,
false
);
// Set inputs val after modal is displayed
modal
.
find
(
'input[name="minimal_stock"]'
).
val
(
product
.
minimal_stock
);
modal
.
find
(
'input[name="actual_stock"]'
).
val
(
product
.
qty_available
);
for
(
let
supplierinfo
of
product
.
suppliersinfo
)
{
modal
.
find
(
`input[supplierinfo_id="
${
supplierinfo
.
id
}
"]`
).
val
(
supplierinfo
.
price
);
}
});
...
...
products/models.py
View file @
2825333f
...
...
@@ -160,6 +160,7 @@ class CagetteProduct(models.Model):
try
:
res
[
"update"
]
=
api
.
update
(
'product.supplierinfo'
,
psi_id
,
f
)
res
[
"psi_id"
]
=
psi_id
except
Exception
as
e
:
res
[
'error'
]
=
str
(
e
)
else
:
...
...
@@ -185,6 +186,7 @@ class CagetteProduct(models.Model):
try
:
res
[
'create'
]
=
api
.
create
(
'product.supplierinfo'
,
f
)
res
[
'psi_id'
]
=
res
[
'create'
]
# consistency between update & create res
except
Exception
as
e
:
res
[
'error'
]
=
str
(
e
)
...
...
@@ -259,13 +261,17 @@ class CagetteProduct(models.Model):
- NPA (ne pas acheter)
- Product is active
- Minimal stock
- price /supplier
"""
res
=
{}
try
:
api
=
OdooAPI
()
# Minimal stock
f
=
{
'minimal_stock'
:
data
[
'minimal_stock'
]}
# Minimal & Actual stock, Active
f
=
{
'minimal_stock'
:
float
(
data
[
'minimal_stock'
]),
'active'
:
not
data
[
'to_archive'
]
}
# NPA
if
'simple-npa'
in
data
[
'npa'
]:
...
...
@@ -286,14 +292,20 @@ class CagetteProduct(models.Model):
f
[
'name'
]
=
re
.
sub
(
r'( \[FDS\])'
,
''
,
current_name
)
if
len
(
data
[
'npa'
])
==
0
:
f
[
'purchase_ok'
]
=
1
# Active
f
[
"active"
]
=
not
data
[
'to_archive'
]
res
[
"update"
]
=
api
.
update
(
'product.template'
,
data
[
'id'
],
f
)
res
[
"update"
]
=
api
.
update
(
'product.template'
,
int
(
data
[
'id'
]),
f
)
# Update suppliers info
res
[
"update_supplierinfo"
]
=
[]
for
supplierinfo
in
data
[
"suppliersinfo"
]:
f
=
{
'price'
:
supplierinfo
[
"price"
]}
res_update_si
=
api
.
update
(
'product.supplierinfo'
,
int
(
supplierinfo
[
'supplierinfo_id'
]),
f
)
res
[
"update_supplierinfo"
]
.
append
(
res_update_si
)
except
Exception
as
e
:
res
[
"error"
]
=
str
(
e
)
coop_logger
.
error
(
"
update_npa_and_minimal_stock
:
%
s
%
s"
,
str
(
e
),
str
(
data
))
coop_logger
.
error
(
"
commit_actions_on_product
:
%
s
%
s"
,
str
(
e
),
str
(
data
))
return
res
class
CagetteProducts
(
models
.
Model
):
"""Initially used to make massive barcode update."""
...
...
@@ -593,7 +605,7 @@ class CagetteProducts(models.Model):
if
supplier_ids
is
not
None
and
len
(
supplier_ids
)
>
0
:
# Get products/supplier relation
f
=
[
"product_tmpl_id"
,
'date_start'
,
'date_end'
,
'package_qty'
,
'price'
,
'name'
,
'product_code'
]
f
=
[
"
id"
,
"
product_tmpl_id"
,
'date_start'
,
'date_end'
,
'package_qty'
,
'price'
,
'name'
,
'product_code'
]
c
=
[[
'name'
,
'in'
,
[
int
(
x
)
for
x
in
supplier_ids
]]]
psi
=
api
.
search_read
(
'product.supplierinfo'
,
c
,
f
)
...
...
@@ -651,6 +663,7 @@ class CagetteProducts(models.Model):
for
psi_item
in
valid_psi
:
if
psi_item
[
"product_tmpl_id"
]
is
not
False
and
psi_item
[
"product_tmpl_id"
][
0
]
==
fp
[
"id"
]:
filtered_products_t
[
i
][
'suppliersinfo'
]
.
append
({
'id'
:
int
(
psi_item
[
"id"
]),
'supplier_id'
:
int
(
psi_item
[
"name"
][
0
]),
'package_qty'
:
psi_item
[
"package_qty"
],
'price'
:
psi_item
[
"price"
],
...
...
products/views.py
View file @
2825333f
...
...
@@ -149,29 +149,48 @@ def commit_actions_on_product(request):
res
=
CagetteProduct
.
commit_actions_on_product
(
data
)
# If stock > 0: do inventory to set stock to 0
do_stock_update
=
False
# If product to archive and stock > 0: do inventory to set stock to 0
if
data
[
"to_archive"
]
is
True
and
product_data
[
"qty_available"
]
!=
0
:
p
=
{
'id'
:
product_data
[
'product_variant_ids'
][
0
],
# Need product id
'uom_id'
:
product_data
[
'uom_id'
],
'qty'
:
0
}
inventory_data
=
{
'name'
:
'Archivage - '
+
product_data
[
'name'
],
'products'
:
[
p
]
}
do_stock_update
=
True
# Else update actual stock if changed
elif
data
[
"qty_available"
]
!=
product_data
[
"qty_available"
]:
p
=
{
'id'
:
product_data
[
'product_variant_ids'
][
0
],
# Need product id
'uom_id'
:
product_data
[
'uom_id'
],
'qty'
:
data
[
"qty_available"
]
}
inventory_data
=
{
'name'
:
'MAJ stock depuis Aide à la Commande - '
+
product_data
[
'name'
],
'products'
:
[
p
]
}
do_stock_update
=
True
if
do_stock_update
is
True
:
try
:
p
=
{
'id'
:
product_data
[
'product_variant_ids'
][
0
],
# Need product id
'uom_id'
:
product_data
[
'uom_id'
],
'qty'
:
-
product_data
[
"qty_available"
]
}
inventory_data
=
{
'name'
:
'Archivage - '
+
product_data
[
'name'
],
'products'
:
[
p
]
}
res_inventory
=
CagetteInventory
.
update_products_stock
(
inventory_data
)
res_inventory
=
CagetteInventory
.
update_products_stock
(
inventory_data
,
3
)
if
res_inventory
[
'errors'
]
or
res_inventory
[
'missed'
]:
res
[
"code"
]
=
"error_stock_update"
res
[
"error"
]
=
res_inventory
[
'errors'
]
return
JsonResponse
(
res
,
status
=
500
)
except
Exception
as
e
:
res
[
"code"
]
=
"error_stock_update"
return
JsonResponse
(
res
,
status
=
500
)
except
Exception
as
e
:
res
[
'error'
]
=
str
(
e
)
coop_logger
.
error
(
"Update npa and minimal stock :
%
s"
,
res
[
'error'
])
...
...
templates/orders/helper.html
View file @
2825333f
...
...
@@ -276,29 +276,53 @@
<hr/>
</div>
<div
id=
"product_price_action_template"
>
<div
class=
"product_price_action"
>
<span
class=
"supplier_name"
></span>
<input
type=
"number"
class=
"product_supplier_price"
name=
""
value=
""
/>
</div>
</div>
<div
id=
"modal_product_actions"
>
Actions sur
<h3><span
class=
"product_name"
></span></h3>
<div
class=
"modal_product_actions_section"
>
<h4
class=
"modal_product_actions_title"
>
NPA
</h4>
<div
class=
"npa-options"
>
<label><input
type=
"checkbox"
name=
"npa-actions"
value=
"simple-npa"
/>
Mettre le produit en NPA
</label>
<label><input
type=
"checkbox"
name=
"npa-actions"
value=
"npa-in-name"
/>
Mettre le produit en NPA et afficher NPA
</label>
<label><input
type=
"checkbox"
name=
"npa-actions"
value=
"fds-in-name"
/>
Mettre le produit en NPA et afficher FDS
</label>
<div
class=
"product_actions_container"
>
<div
class=
"product_actions_section"
>
<div
class=
"product_actions_column"
>
<h4
class=
"modal_product_actions_title"
>
NPA
</h4>
<div
class=
"npa-options"
>
<label><input
type=
"checkbox"
name=
"npa-actions"
value=
"simple-npa"
/>
Mettre le produit en NPA
</label>
<label><input
type=
"checkbox"
name=
"npa-actions"
value=
"npa-in-name"
/>
Mettre le produit en NPA et afficher NPA
</label>
<label><input
type=
"checkbox"
name=
"npa-actions"
value=
"fds-in-name"
/>
Mettre le produit en NPA et afficher FDS
</label>
</div>
</div>
<div
class=
"product_actions_column"
>
<h4
class=
"modal_product_actions_title"
>
Archiver le produit
</h4>
<label
class=
"checkbox_action_disabled"
><input
type=
"checkbox"
name=
"archive-action"
value=
"archive"
disabled
/>
Archiver
</label>
<div
class=
"tooltip"
>
<i
class=
'main fa fa-info-circle'
></i>
<span
class=
"tooltiptext tooltip-xl tt_twolines"
>
Un produit ne peut pas être archivé si une quantité entrante est prévue.
</span>
</div>
</div>
</div>
</div>
<div
class=
"modal_product_actions_section"
>
<h4
class=
"modal_product_actions_title"
>
Archiver le produit
</h4>
<label
class=
"checkbox_action_disabled"
><input
type=
"checkbox"
name=
"archive-action"
value=
"archive"
disabled
/>
Archiver
</label>
<div
class=
"tooltip"
>
<i
class=
'main fa fa-info-circle'
></i>
<span
class=
"tooltiptext tooltip-xl tt_twolines"
>
Un produit ne peut pas être archivé si une quantité entrante est prévue.
</span>
<div
class=
"product_actions_section"
>
<div
class=
"product_actions_column"
>
<h4
class=
"modal_product_actions_title"
>
Stock minimum
</h4>
<input
type=
"number"
name=
"minimal_stock"
value=
""
/>
</div>
<div
class=
"product_actions_column"
>
<h4
class=
"modal_product_actions_title"
>
Stock réel
</h4>
<input
type=
"number"
name=
"actual_stock"
value=
""
/>
</div>
</div>
<div
class=
"product_actions_section"
>
<div
class=
"product_actions_full_column"
>
<h4
class=
"modal_product_actions_title product_prices_title"
>
Prix
</h4>
<i
class=
"product_prices_title_label"
>
(par fournisseur dans cette commande)
</i>
<div
class=
"product_prices_area"
></div>
</div>
</div>
</div>
<div
class=
"modal_product_actions_section"
>
<h4
class=
"modal_product_actions_title"
>
Stock minimum
</h4>
<input
type=
"number"
name=
"minimal_stock"
value=
""
/>
</div>
</div>
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment