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
0
Merge Requests
0
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
Alexis AOUN
third-party
Commits
a15908ef
Commit
a15908ef
authored
3 years ago
by
Damien Moulard
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
create product orders in odoo
parent
6a661024
dev_principale
…
Reception_poids
dev_cooperatic
fix_remove-qty-edition
No related merge requests found
Hide whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
594 additions
and
78 deletions
+594
-78
models.py
orders/models.py
+75
-0
oders_helper_style.css
orders/static/css/oders_helper_style.css
+73
-5
orders_helper.js
orders/static/js/orders_helper.js
+316
-57
urls.py
orders/urls.py
+2
-0
views.py
orders/views.py
+45
-2
models.py
products/models.py
+19
-10
helper.html
templates/orders/helper.html
+64
-4
No files found.
orders/models.py
View file @
a15908ef
...
...
@@ -222,6 +222,81 @@ class Order(models.Model):
labels_data
[
'total'
]
+=
l
[
'product_qty'
]
return
labels_data
def
get_order_attachment_id
(
self
):
res
=
{}
f
=
[
"id"
]
c
=
[[
'res_model'
,
'='
,
'purchase.order'
],
[
'res_id'
,
'='
,
self
.
id
],
[
'type'
,
'in'
,
[
'binary'
,
'url'
]]]
try
:
attachment
=
self
.
o_api
.
search_read
(
'ir.attachment'
,
c
,
f
)
res
=
attachment
[
0
]
except
Exception
as
e
:
res
[
"id_po"
]
=
self
.
id
res
[
"error"
]
=
str
(
e
)
return
res
@staticmethod
def
create
(
supplier_id
,
date_planned
,
order_lines
):
order_data
=
{
"partner_id"
:
int
(
supplier_id
),
"partner_ref"
:
False
,
"currency_id"
:
1
,
"date_order"
:
datetime
.
datetime
.
now
()
.
strftime
(
"
%
Y-
%
m-
%
d
%
H:
%
M:
%
S"
),
"origin"
:
"Aide à la commande"
,
"company_id"
:
1
,
"order_line"
:
[],
"notes"
:
False
,
"date_planned"
:
date_planned
,
"picking_type_id"
:
1
,
"dest_address_id"
:
False
,
"incoterm_id"
:
False
,
"payment_term_id"
:
False
,
"fiscal_position_id"
:
False
,
"message_follower_ids"
:
False
,
"message_ids"
:
False
}
for
line
in
order_lines
:
order_data
[
"order_line"
]
.
append
(
[
0
,
False
,
{
"package_qty"
:
line
[
"package_qty"
],
"price_policy"
:
"uom"
,
"indicative_package"
:
True
,
"product_id"
:
line
[
"product_variant_ids"
][
0
],
"name"
:
line
[
"name"
],
"date_planned"
:
date_planned
,
"account_analytic_id"
:
False
,
"product_qty_package"
:
line
[
"product_qty_package"
],
"product_qty"
:
line
[
"product_qty"
],
"product_uom"
:
line
[
"product_uom"
],
"price_unit"
:
line
[
"price_unit"
],
"discount"
:
0
,
"taxes_id"
:
[
[
6
,
False
,
line
[
"supplier_taxes_id"
]
]
]
}
]
)
api
=
OdooAPI
()
id_po
=
api
.
create
(
'purchase.order'
,
order_data
)
res_confirm
=
api
.
execute
(
'purchase.order'
,
'button_confirm'
,
[
id_po
])
res
=
{
'id_po'
:
id_po
,
'confirm_po'
:
True
}
return
res
class
Orders
(
models
.
Model
):
@staticmethod
...
...
This diff is collapsed.
Click to expand it.
orders/static/css/oders_helper_style.css
View file @
a15908ef
...
...
@@ -72,14 +72,20 @@
right
:
0
;
}
/* --
Supplier form
*/
#
supplier_form
_container
{
/* --
Order data
*/
#
order_data
_container
{
margin-top
:
30px
;
display
:
flex
;
justify-content
:
space-evenly
;
}
#supplier_input
{
width
:
500px
;
margin-right
:
10px
;
width
:
350px
;
border-radius
:
5px
;
}
#date_planned_input
{
margin-left
:
40px
;
border-radius
:
5px
;
}
...
...
@@ -89,7 +95,9 @@
}
#products_table_filter
input
{
height
:
40px
;
height
:
35px
;
width
:
300px
;
border-radius
:
10px
;
}
#table_header_select_all
{
...
...
@@ -125,6 +133,14 @@
cursor
:
pointer
;
}
/* -- Bottom action button */
#orders_creation_area
{
display
:
flex
;
justify-content
:
space-between
;
margin
:
15px
0
35px
0
;
}
/* -- Suppliers list */
#suppliers_container
{
display
:
flex
;
...
...
@@ -142,4 +158,55 @@
color
:
red
;
margin-left
:
5px
;
cursor
:
pointer
;
}
/* - Orders created screen */
.order_created_header
{
margin-top
:
15px
;
margin-bottom
:
40px
;
}
#created_orders_area
{
display
:
flex
;
flex-wrap
:
wrap
;
justify-content
:
space-evenly
;
}
.new_order_item
{
display
:
flex
;
flex-direction
:
column
;
align-items
:
center
;
margin-top
:
20px
;
}
.download_order_file
{
margin-top
:
10px
;
}
.download_order_file_button
:hover
{
text-decoration
:
none
;
color
:
white
;
}
#recap_delivery_date
{
font-weight
:
bold
;
}
.mail_example_container
{
display
:
flex
;
flex-direction
:
column
;
align-items
:
center
;
width
:
30%
;
margin
:
0
auto
;
}
.mail_type_text
{
width
:
100%
;
}
.mail_example
{
background-color
:
#e7e9ed
;
width
:
100%
;
padding
:
15px
;
}
\ No newline at end of file
This diff is collapsed.
Click to expand it.
orders/static/js/orders_helper.js
View file @
a15908ef
...
...
@@ -7,7 +7,8 @@ var suppliers_list = [],
sync
=
null
,
order_doc
=
{
_id
:
null
,
last_update
:
{
date_planned
:
null
,
last_update
:
{
timestamp
:
null
,
fingerprint
:
null
},
...
...
@@ -15,7 +16,9 @@ var suppliers_list = [],
selected_suppliers
:
[],
selected_rows
:
[]
},
fingerprint
=
null
;
fingerprint
=
null
,
date_format
=
"dd/mm/yy"
product_orders
=
[];
/* - UTILS */
...
...
@@ -29,6 +32,7 @@ function reset_data() {
selected_rows
=
[],
order_doc
=
{
_id
:
null
,
date_planned
:
null
,
last_update
:
{
timestamp
:
null
,
fingerprint
:
null
...
...
@@ -96,7 +100,6 @@ function add_supplier() {
selected_suppliers
.
push
(
supplier
);
let
url
=
"/orders/get_supplier_products"
;
url
+=
"?sid="
+
encodeURIComponent
(
supplier
.
id
);
// Fetch supplier products
...
...
@@ -110,7 +113,7 @@ function add_supplier() {
save_supplier_products
(
supplier
,
data
.
res
.
products
);
update_main_screen
();
$
(
"#supplier_input"
).
val
(
""
);
update_order
();
update_
cdb_
order
();
closeModal
();
},
error
:
function
(
data
)
{
...
...
@@ -139,14 +142,14 @@ function remove_supplier(supplier_id) {
// Remove the supplier from the products suppliers list
for
(
const
i
in
products
)
{
products
[
i
].
suppliers
=
products
[
i
].
suppliers
.
filter
(
supplier
=>
supplier
.
id
!=
supplier_id
);
products
[
i
].
suppliers
info
=
products
[
i
].
suppliersinfo
.
filter
(
supplier
=>
supplier
.
supplier_
id
!=
supplier_id
);
}
// Remove products only associated to this product
products
=
products
.
filter
(
product
=>
product
.
suppliers
.
length
>
0
);
products
=
products
.
filter
(
product
=>
product
.
suppliers
info
.
length
>
0
);
update_main_screen
();
update_order
();
update_
cdb_
order
();
}
...
...
@@ -165,7 +168,7 @@ function save_supplier_product_association(product, supplier, cell) {
supplier_id
:
supplier
.
id
};
//
Fetch supplier products
//
Send request to create association
$
.
ajax
({
type
:
"POST"
,
url
:
"/orders/associate_supplier_to_product"
,
...
...
@@ -175,6 +178,7 @@ function save_supplier_product_association(product, supplier, cell) {
data
:
JSON
.
stringify
(
data
),
success
:
()
=>
{
// Save relation locally
// TODO: save supplierinfo in product
save_supplier_products
(
supplier
,
[
product
]);
// Update table
...
...
@@ -216,10 +220,10 @@ function save_supplier_products(supplier, new_products) {
let
index
=
products
.
findIndex
(
p
=>
p
.
id
===
np
.
id
);
if
(
index
===
-
1
)
{
np
.
suppliers
=
[{
...
supplier
}];
products
.
push
(
np
);
}
else
{
products
[
index
].
suppliers
.
push
({
...
supplier
});
np_supplierinfo
=
np
.
suppliersinfo
[
0
];
products
[
index
].
suppliersinfo
.
push
(
np_supplierinfo
);
}
}
}
...
...
@@ -234,9 +238,9 @@ function save_supplier_products(supplier, new_products) {
function
save_product_supplier_qty
(
prod_id
,
supplier_id
,
val
)
{
for
(
const
i
in
products
)
{
if
(
products
[
i
].
id
==
prod_id
)
{
for
(
const
j
in
products
[
i
].
suppliers
)
{
if
(
products
[
i
].
suppliers
[
j
].
id
==
supplier_id
)
{
products
[
i
].
suppliers
[
j
].
qty
=
val
;
for
(
const
j
in
products
[
i
].
suppliers
info
)
{
if
(
products
[
i
].
suppliers
info
[
j
].
supplier_
id
==
supplier_id
)
{
products
[
i
].
suppliers
info
[
j
].
qty
=
val
;
break
;
}
}
...
...
@@ -252,7 +256,7 @@ function save_product_supplier_qty(prod_id, supplier_id, val) {
* @returns boolean
*/
function
is_product_related_to_supplier
(
product
,
supplier
)
{
return
product
.
suppliers
.
find
(
s
=>
s
.
id
===
supplier
.
id
)
!==
undefined
;
return
product
.
suppliers
info
.
find
(
s
=>
s
.
supplier_
id
===
supplier
.
id
)
!==
undefined
;
}
/* - PRODUCT */
...
...
@@ -282,7 +286,7 @@ function set_product_npa(p_id, npa) {
success
:
()
=>
{
const
index
=
products
.
findIndex
(
p
=>
p
.
id
==
p_id
);
products
[
index
].
purchase_ok
=
data
[
"purchase_ok"
];
update_order
();
update_
cdb_
order
();
closeModal
();
},
...
...
@@ -325,9 +329,9 @@ function generate_inventory() {
const
product
=
products
.
find
(
p
=>
p
.
id
==
selected_data
[
i
].
id
);
data
.
lines
.
push
(
product
.
id
);
for
(
const
supplier
of
product
.
suppliers
)
{
if
(
data
.
partners_id
.
indexOf
(
supplier
.
id
)
===
-
1
)
{
data
.
partners_id
.
push
(
supplier
.
id
);
for
(
const
supplier
info
of
product
.
suppliersinfo
)
{
if
(
data
.
partners_id
.
indexOf
(
supplier
info
.
supplier_
id
)
===
-
1
)
{
data
.
partners_id
.
push
(
supplier
info
.
supplier_
id
);
}
}
}
...
...
@@ -351,10 +355,10 @@ function generate_inventory() {
// Give time for modal to fade
setTimeout
(
function
()
{
$
.
notify
(
$
(
'#do_inventory'
)
.
notify
(
"Inventaire créé !"
,
{
globalPosition
:
"
top left
"
,
globalPosition
:
"
bottom center
"
,
className
:
"success"
}
);
...
...
@@ -439,13 +443,18 @@ function order_pill_on_click() {
/**
* Create an order in couchdb if the name doesn't exist
*/
function
create_order
()
{
function
create_
cdb_
order
()
{
const
order_name
=
$
(
"#new_order_name"
).
val
();
order_doc
.
_id
=
order_name
;
order_doc
.
last_update
=
{
timestamp
:
Date
.
now
(),
fingerprint
:
fingerprint
};
dbc
.
put
(
order_doc
,
function
callback
(
err
,
result
)
{
if
(
!
err
)
{
order_doc
.
_rev
=
result
.
rev
;
update_main_screen
();
switch_screen
();
}
else
{
if
(
err
.
status
==
409
)
{
...
...
@@ -459,7 +468,7 @@ function create_order() {
/**
* Update order data of an existing order in couchdb
*/
function
update_order
()
{
function
update_
cdb_
order
()
{
order_doc
.
products
=
products
;
order_doc
.
selected_suppliers
=
selected_suppliers
;
...
...
@@ -479,6 +488,146 @@ function update_order() {
});
}
/**
* Create the Product Orders in Odoo
*/
function
create_orders
()
{
openModal
();
let
orders_data
=
{
"date_planned"
:
order_doc
.
date_planned
,
"suppliers_data"
:
{}
};
// Prepare data: get products where a qty is set
for
(
let
p
of
products
)
{
for
(
let
p_supplierinfo
of
p
.
suppliersinfo
)
{
// If a qty is set for a supplier for a product
if
(
'qty'
in
p_supplierinfo
)
{
const
supplier_id
=
p_supplierinfo
.
supplier_id
;
// Create entry for this supplier in data object if doesn't exist
if
(
orders_data
.
suppliers_data
[
supplier_id
]
===
undefined
)
{
orders_data
.
suppliers_data
[
supplier_id
]
=
[];
}
orders_data
.
suppliers_data
[
supplier_id
].
push
({
'package_qty'
:
p_supplierinfo
.
package_qty
,
'product_id'
:
p
.
id
,
'name'
:
p
.
name
,
'product_qty_package'
:
p_supplierinfo
.
qty
,
'product_qty'
:
p_supplierinfo
.
qty
*
p_supplierinfo
.
package_qty
,
'product_uom'
:
p
.
uom_id
[
0
],
'price_unit'
:
p_supplierinfo
.
price
,
'supplier_taxes_id'
:
p
.
supplier_taxes_id
,
'product_variant_ids'
:
p
.
product_variant_ids
})
}
}
}
if
(
Object
.
keys
(
orders_data
.
suppliers_data
).
length
===
0
)
{
closeModal
();
alert
(
"Commande non créée : vous n'avez rentré aucune quantité !"
);
return
-
1
;
}
$
.
ajax
({
type
:
"POST"
,
url
:
"/orders/create_orders"
,
dataType
:
"json"
,
traditional
:
true
,
contentType
:
"application/json; charset=utf-8"
,
data
:
JSON
.
stringify
(
orders_data
),
success
:
(
result
)
=>
{
$
(
'#recap_delivery_date'
).
text
(
$
(
'#date_planned_input'
).
val
());
// Display new orders
for
(
let
new_order
of
result
.
res
.
created
)
{
const
supplier_name
=
suppliers_list
.
find
(
s
=>
s
.
id
==
new_order
.
supplier_id
).
display_name
;
product_orders
.
push
({
'id'
:
new_order
.
id_po
,
'supplier_id'
:
new_order
.
supplier_id
,
'supplier_name'
:
supplier_name
})
let
new_order_template
=
$
(
"#templates #new_order_item_template"
);
new_order_template
.
find
(
".new_order_supplier_name"
).
text
(
supplier_name
);
new_order_template
.
find
(
".new_order_po"
).
text
(
`PO
${
new_order
.
id_po
}
`
);
new_order_template
.
find
(
".download_order_file_button"
).
attr
(
'id'
,
`download_attachment_
${
new_order
.
id_po
}
`
);
$
(
'#created_orders_area'
).
append
(
new_order_template
.
html
());
}
// Prepare buttons to download order attachment
get_order_attachments
();
// Clear data
order_doc
.
_deleted
=
true
;
update_cdb_order
();
reset_data
();
update_order_selection_screen
();
switch_screen
(
'orders_created'
);
closeModal
();
},
error
:
function
(
data
)
{
let
msg
=
"erreur serveur lors de la création des product orders"
err
=
{
msg
:
msg
,
ctx
:
'save_supplier_product_association'
,
data
:
orders_data
};
if
(
typeof
data
.
responseJSON
!=
'undefined'
&&
typeof
data
.
responseJSON
.
error
!=
'undefined'
)
{
err
.
msg
+=
' : '
+
data
.
responseJSON
.
error
;
}
report_JS_error
(
err
,
'orders'
);
closeModal
();
alert
(
'Erreur lors de la création des commandes. Veuillez ré-essayer plus tard.'
);
}
});
}
/**
* Get the PO attachment id.
* Display download button when fetch is succesful.
* The file might not be created soon enough, so try again after 10s if error server
*/
function
get_order_attachments
()
{
if
(
product_orders
.
length
>
0
)
{
let
po_ids
=
product_orders
.
map
(
po
=>
po
.
id
);
$
.
ajax
({
type
:
'GET'
,
url
:
"/orders/get_orders_attachment"
,
data
:
{
'po_ids'
:
po_ids
},
dataType
:
"json"
,
traditional
:
true
,
contentType
:
"application/json; charset=utf-8"
,
success
:
function
(
data
)
{
for
(
let
res_po
of
data
.
res
)
{
$
(
`#download_attachment_
${
res_po
.
id_po
}
`
).
attr
(
'href'
,
`
${
odoo_server
}
/web/content/
${
res_po
.
id_attachment
}
?download=true`
)
}
$
(
'#created_orders_area .download_order_file_loading'
).
hide
()
$
(
'#created_orders_area .download_order_file_button'
).
show
()
},
error
:
function
(
data
)
{
console
.
log
(
data
);
$
.
notify
(
"Échec de la récupération du lien de téléchargement des fichiers. Nouvelle tentative dans 10s."
,
{
globalPosition
:
"top right"
,
className
:
"error"
}
);
setTimeout
(
get_order_attachments
,
10000
);
}
});
}
}
/* - DISPLAY */
...
...
@@ -487,7 +636,7 @@ function goto_main_screen(doc) {
products
=
order_doc
.
products
;
selected_suppliers
=
order_doc
.
selected_suppliers
;
update_order
();
update_
cdb_
order
();
update_main_screen
();
switch_screen
();
}
...
...
@@ -503,7 +652,8 @@ function back() {
* @returns String
*/
function
supplier_column_name
(
supplier
)
{
return
`qty_supplier_
${
supplier
.
id
}
`
;
const
supplier_id
=
(
'supplier_id'
in
supplier
)
?
supplier
.
supplier_id
:
supplier
.
id
return
`qty_supplier_
${
supplier_id
}
`
;
}
/**
...
...
@@ -572,7 +722,7 @@ function prepare_datatable_data(product_ids = []) {
};
// If product related to supplier: qty or null (qty to be set)
for
(
product_supplier
of
product
.
suppliers
)
{
for
(
product_supplier
of
product
.
suppliers
info
)
{
let
supplier_qty
=
(
"qty"
in
product_supplier
)
?
product_supplier
.
qty
:
null
;
item
[
supplier_column_name
(
product_supplier
)]
=
supplier_qty
;
...
...
@@ -695,6 +845,8 @@ function prepare_datatable_columns() {
function
display_products
()
{
if
(
products
.
length
==
0
)
{
$
(
'.main'
).
hide
();
$
(
'#create_orders'
).
hide
();
$
(
'#do_inventory'
).
hide
();
return
-
1
;
}
...
...
@@ -736,6 +888,8 @@ function display_products() {
});
$
(
'.main'
).
show
();
$
(
'#create_orders'
).
show
();
$
(
'#do_inventory'
).
show
();
// On inputs change
$
(
'#products_table'
).
on
(
'input'
,
'tbody td .product_qty_input'
,
function
()
{
...
...
@@ -756,7 +910,7 @@ function display_products() {
const
new_row_data
=
prepare_datatable_data
([
product
.
id
])[
0
];
products_table
.
row
(
$
(
this
).
closest
(
'tr'
)).
data
(
new_row_data
).
draw
();
update_order
();
update_
cdb_
order
();
}
});
...
...
@@ -899,6 +1053,15 @@ function update_main_screen() {
return
0
;
});
}
if
(
order_doc
.
date_planned
!==
null
)
{
// Switch format from yy-mm-dd hh:mm:ss to readable dd/mm/yy
let
date_to_format
=
order_doc
.
date_planned
.
split
(
' '
)[
0
];
let
readable_date
=
date_to_format
.
split
(
'-'
).
reverse
().
join
(
'/'
);
$
(
"#date_planned_input"
).
val
(
readable_date
);
}
else
{
$
(
"#date_planned_input"
).
val
(
''
);
}
}
/**
...
...
@@ -936,35 +1099,47 @@ function update_order_selection_screen() {
}
/**
* Switch screen between order selection & main screens
* @param {String} direction target screen
* Switch between screens
* @param {String} direction target screen : order_selection | main_screen | orders_created
* @param {String} from source screen : order_selection | main_screen | orders_created
*/
function
switch_screen
(
direction
=
'main_screen'
)
{
let
oldBox
=
null
;
let
newBox
=
null
;
let
outerWidth
=
null
;
if
(
direction
==
'main_screen'
)
{
oldBox
=
$
(
"#select_order_content"
);
newBox
=
$
(
"#main_content"
);
outerWidth
=
oldBox
.
outerWidth
(
true
);
function
switch_screen
(
direction
=
'main_screen'
,
from
=
'main_screen'
)
{
if
(
direction
===
'orders_created'
)
{
$
(
'#main_content'
).
hide
();
$
(
'#orders_created'
).
show
();
}
else
{
oldBox
=
$
(
"#main_content"
);
newBox
=
$
(
"#select_order_content"
);
outerWidth
=
-
oldBox
.
outerWidth
(
true
);
// Animated transition
let
oldBox
=
null
;
let
newBox
=
null
;
let
outerWidth
=
null
;
if
(
direction
===
'main_screen'
)
{
oldBox
=
$
(
"#select_order_content"
);
newBox
=
$
(
"#main_content"
);
outerWidth
=
oldBox
.
outerWidth
(
true
);
}
else
{
if
(
from
===
'orders_created'
)
{
oldBox
=
$
(
"#orders_created"
);
}
else
{
oldBox
=
$
(
"#main_content"
);
}
newBox
=
$
(
"#select_order_content"
);
outerWidth
=
-
oldBox
.
outerWidth
(
true
);
}
// Display the new box and place it on the right of the screen
newBox
.
css
({
"left"
:
outerWidth
+
"px"
,
"right"
:
-
outerWidth
+
"px"
,
"display"
:
""
});
// Make the old content slide to the left
oldBox
.
animate
({
"left"
:
-
outerWidth
+
"px"
,
"right"
:
outerWidth
+
"px"
},
800
,
function
()
{
// Hide old content after animation
oldBox
.
css
({
"left"
:
""
,
"right"
:
""
,
"display"
:
"none"
});
});
// Slide new box to regular place
newBox
.
animate
({
"left"
:
""
,
"right"
:
""
},
800
);
}
// Display the new box and place it on the right of the screen
newBox
.
css
({
"left"
:
outerWidth
+
"px"
,
"right"
:
-
outerWidth
+
"px"
,
"display"
:
""
});
// Make the old content slide to the left
oldBox
.
animate
({
"left"
:
-
outerWidth
+
"px"
,
"right"
:
outerWidth
+
"px"
},
800
,
function
()
{
// Hide old content after animation
oldBox
.
css
({
"left"
:
""
,
"right"
:
""
,
"display"
:
"none"
});
});
// Slide new box to regular place
newBox
.
animate
({
"left"
:
""
,
"right"
:
""
},
800
);
}
...
...
@@ -985,8 +1160,8 @@ $(document).ready(function() {
sync
.
on
(
'change'
,
function
(
info
)
{
if
(
info
.
direction
===
"pull"
)
{
for
(
const
doc
of
info
.
change
.
docs
)
{
// If current order was modified somewhere else
if
(
order_doc
.
_id
===
doc
.
_id
&&
order_doc
.
_rev
!==
doc
.
_rev
)
{
if
(
order_doc
.
_id
===
doc
.
_id
&&
(
order_doc
.
_rev
!==
doc
.
_rev
||
doc
.
_deleted
===
true
))
{
// If current order was modified somewhere else
$
.
notify
(
"Un autre navigateur est en train de modifier cette commande !"
,
{
...
...
@@ -994,8 +1169,11 @@ $(document).ready(function() {
className
:
"error"
}
);
update_order_selection_screen
();
back
();
break
;
}
else
if
(
doc
.
_deleted
===
true
)
{
update_order_selection_screen
();
}
}
}
...
...
@@ -1008,7 +1186,7 @@ $(document).ready(function() {
console
.
log
(
err
);
});
// Main screen
listeners
// Main screen
$
(
"#supplier_form"
).
on
(
"submit"
,
function
(
e
)
{
e
.
preventDefault
();
add_supplier
();
...
...
@@ -1018,16 +1196,97 @@ $(document).ready(function() {
generate_inventory
();
});
$
(
'#back_to_order_selection'
).
on
(
'click'
,
function
()
{
$
(
'#back_to_order_selection
_from_main
'
).
on
(
'click'
,
function
()
{
back
();
});
$
(
'#create_orders'
).
on
(
'click'
,
function
()
{
if
(
order_doc
.
date_planned
===
null
)
{
alert
(
"Veuillez rentrer une date de livraison prévue."
)
return
-
1
}
let
modal_create_order
=
$
(
'#templates #modal_create_order'
);
openModal
(
modal_create_order
.
html
(),
()
=>
{
create_orders
();
},
'Valider'
,
false
);
});
$
.
datepicker
.
regional
[
'fr'
]
=
{
monthNames
:
[
'Janvier'
,
'Fevrier'
,
'Mars'
,
'Avril'
,
'Mai'
,
'Juin'
,
'Juillet'
,
'Aout'
,
'Septembre'
,
'Octobre'
,
'Novembre'
,
'Decembre'
],
dayNamesMin
:
[
'Di'
,
'Lu'
,
'Ma'
,
'Me'
,
'Je'
,
'Ve'
,
'Sa'
],
dateFormat
:
date_format
,
};
$
.
datepicker
.
setDefaults
(
$
.
datepicker
.
regional
[
'fr'
]);
const
tomorrow
=
new
Date
()
tomorrow
.
setDate
(
tomorrow
.
getDate
()
+
1
)
$
(
"#date_planned_input"
)
.
datepicker
({
defaultDate
:
"+1d"
,
minDate
:
tomorrow
})
.
on
(
'change'
,
function
()
{
try
{
// When date input changes, try to read date
$
.
datepicker
.
parseDate
(
date_format
,
$
(
this
).
val
());
// No exception raised: date is valid.
// Change format from readable (dd/mm/yy) to ISO (yy-mm-dd)
let
formatted_date
=
$
(
this
).
val
().
split
(
'/'
).
reverse
().
join
(
'-'
)
+
' 00:00:00'
;
// Update doc if changed
if
(
formatted_date
!==
order_doc
.
date_planned
)
{
order_doc
.
date_planned
=
formatted_date
;
update_cdb_order
();
}
}
catch
(
error
)
{
alert
(
'Date invalide'
);
$
(
this
).
val
(
''
);
order_doc
.
date_planned
=
null
;
update_cdb_order
();
}
});
// Order selection screen
update_order_selection_screen
();
$
(
"#new_order_form"
).
on
(
"submit"
,
function
(
e
)
{
e
.
preventDefault
();
create_order
();
create_cdb_order
();
});
// Orders created screen
$
(
'#back_to_order_selection_from_orders_created'
).
on
(
'click'
,
function
()
{
switch_screen
(
'order_selection'
,
'orders_created'
);
});
// Get suppliers
...
...
This diff is collapsed.
Click to expand it.
orders/urls.py
View file @
a15908ef
...
...
@@ -13,4 +13,6 @@ urlpatterns = [
url
(
r'^get_suppliers$'
,
views
.
get_suppliers
),
url
(
r'^get_supplier_products$'
,
views
.
get_supplier_products
),
url
(
r'^associate_supplier_to_product$'
,
views
.
associate_supplier_to_product
),
url
(
r'^create_orders$'
,
views
.
create_orders
),
url
(
r'^get_orders_attachment$'
,
views
.
get_orders_attachment
),
]
This diff is collapsed.
Click to expand it.
orders/views.py
View file @
a15908ef
...
...
@@ -7,6 +7,7 @@ from products.models import CagetteProduct, CagetteProducts
from
openpyxl
import
Workbook
from
openpyxl.writer.excel
import
save_virtual_workbook
import
datetime
def
as_text
(
value
):
return
str
(
value
)
if
value
is
not
None
else
""
...
...
@@ -17,7 +18,8 @@ def helper(request):
context
=
{
'title'
:
'Aide à la commande'
,
'couchdb_server'
:
settings
.
COUCHDB
[
'url'
],
'db'
:
settings
.
COUCHDB
[
'dbs'
][
'orders'
]
'db'
:
settings
.
COUCHDB
[
'dbs'
][
'orders'
],
'odoo_server'
:
settings
.
ODOO
[
'url'
]
}
template
=
loader
.
get_template
(
'orders/helper.html'
)
...
...
@@ -59,6 +61,48 @@ def associate_supplier_to_product(request):
return
JsonResponse
({
'res'
:
res
})
def
create_orders
(
request
):
""" Create products orders """
res
=
{
"created"
:
[]
}
try
:
data
=
json
.
loads
(
request
.
body
.
decode
())
# suppliers id are keys in request data
for
supplier_id
in
data
[
"suppliers_data"
]
.
keys
():
res_created
=
Order
.
create
(
supplier_id
,
data
[
"date_planned"
],
data
[
"suppliers_data"
][
supplier_id
])
res_created
[
"supplier_id"
]
=
supplier_id
res
[
"created"
]
.
append
(
res_created
)
except
Exception
as
e
:
res
[
"error"
]
=
str
(
e
)
return
JsonResponse
(
res
,
status
=
500
)
return
JsonResponse
({
'res'
:
res
})
def
get_orders_attachment
(
request
):
""" Get order attachment: order file created after PO is finalized """
res
=
[]
po_ids
=
request
.
GET
.
getlist
(
'po_ids'
)
for
id_po
in
po_ids
:
m
=
Order
(
int
(
id_po
))
attachment
=
m
.
get_order_attachment_id
()
if
'error'
in
attachment
:
res
.
append
(
attachment
)
else
:
res
.
append
({
'id_po'
:
id_po
,
'id_attachment'
:
attachment
[
"id"
]
})
for
item
in
res
:
if
'error'
in
item
:
return
JsonResponse
(
res
,
status
=
500
)
return
JsonResponse
({
'res'
:
res
})
def
export_one
(
request
,
oid
):
msg
=
''
try
:
...
...
@@ -66,7 +110,6 @@ def export_one(request, oid):
order
=
Order
(
oid
)
order_data
=
order
.
export
()
if
(
'success'
in
order_data
)
and
(
order_data
[
'success'
]
is
True
):
import
datetime
now
=
datetime
.
datetime
.
now
()
taxes
=
0
company_name
=
''
...
...
This diff is collapsed.
Click to expand it.
products/models.py
View file @
a15908ef
...
...
@@ -436,7 +436,7 @@ class CagetteProducts(models.Model):
today
=
datetime
.
date
.
today
()
.
strftime
(
"
%
Y-
%
m-
%
d"
)
# Get products/supplier relation
f
=
[
"product_tmpl_id"
,
'date_start'
,
'date_end'
,
'package_qty'
]
f
=
[
"product_tmpl_id"
,
'date_start'
,
'date_end'
,
'package_qty'
,
'price'
]
c
=
[[
'name'
,
'='
,
int
(
supplier_id
)]]
psi
=
api
.
search_read
(
'product.supplierinfo'
,
c
,
f
)
...
...
@@ -449,21 +449,30 @@ class CagetteProducts(models.Model):
ptids
.
append
(
p
[
"product_tmpl_id"
][
0
])
# Get products templates
f
=
[
"id"
,
"state"
,
"name"
,
"default_code"
,
"qty_available"
,
"incoming_qty"
,
"uom_id"
,
"purchase_ok"
]
# TODO fetch only 'purchase_ok' products ?
f
=
[
"id"
,
"state"
,
"name"
,
"default_code"
,
"qty_available"
,
"incoming_qty"
,
"uom_id"
,
"purchase_ok"
,
"supplier_taxes_id"
,
"product_variant_ids"
]
c
=
[[
'id'
,
'in'
,
ptids
],
[
'purchase_ok'
,
'='
,
True
]]
products_t
=
api
.
search_read
(
'product.template'
,
c
,
f
)
filtered_products_t
=
[
p
for
p
in
products_t
if
p
[
"state"
]
!=
"end"
and
p
[
"state"
]
!=
"obsolete"
]
# Add
package qty
to product data
# Add
supplier data
to product data
for
i
,
fp
in
enumerate
(
filtered_products_t
):
psi_item
=
next
(
item
for
item
in
psi
if
item
[
"product_tmpl_id"
]
is
not
False
and
item
[
"product_tmpl_id"
][
0
]
==
fp
[
"id"
])
filtered_products_t
[
i
][
'supplierinfo'
]
=
{
'supplier_id'
:
supplier_id
,
'package_qty'
:
psi_item
[
"package_qty"
]
}
# Note: if product.product is needed, get "product_variant_ids" from product template
filtered_products_t
[
i
][
'suppliersinfo'
]
=
[{
'supplier_id'
:
int
(
supplier_id
),
'package_qty'
:
psi_item
[
"package_qty"
],
'price'
:
psi_item
[
"price"
]
}]
res
[
"products"
]
=
filtered_products_t
except
Exception
as
e
:
...
...
This diff is collapsed.
Click to expand it.
templates/orders/helper.html
View file @
a15908ef
...
...
@@ -24,17 +24,19 @@
</form>
</div>
<div
id=
"existing_orders_area"
>
<h2>
Ou, continuer une commande e
xistante
</h2>
<h2>
Ou, continuer une commande e
n cours de création
</h2>
<div
id=
"existing_orders"
></div>
</div>
</div>
<div
id=
"main_content"
class=
"page_content"
style=
"display:none;"
>
<div
id=
"back_to_order_selection"
>
<div
id=
"back_to_order_selection
_from_main
"
>
<button
type=
"button"
class=
"btn--danger"
><i
class=
"fas fa-arrow-left"
></i>
Retour
</button>
</div>
<div
id=
"actions_buttons_area"
>
<button
type=
"button"
class=
'btn--primary'
id=
"do_inventory"
>
Faire un inventaire
</button>
<button
type=
"button"
class=
'btn--primary'
id=
"do_inventory"
style=
"display:none;"
>
Faire un inventaire
</button>
</div>
<div
class=
"header txtcenter"
>
...
...
@@ -42,11 +44,12 @@
<i>
Commande :
<span
class=
"order_name_container"
></span></i>
</div>
<div
class=
"txtcenter"
id=
"
supplier_form
_container"
>
<div
class=
"txtcenter"
id=
"
order_data
_container"
>
<form
action=
"javascript:;"
id=
"supplier_form"
>
<input
type=
"text"
name=
"supplier"
id=
"supplier_input"
placeholder=
"Rechercher un fournisseur par son nom"
>
<button
type=
"submit"
class=
'btn--primary'
>
Ajouter le fournisseur
</button>
</form>
<input
type=
"text"
name=
"date_planned"
id=
"date_planned_input"
placeholder=
"Date de livraison souhaitée"
>
</div>
<div
class=
"txtcenter"
id=
"suppliers_container"
></div>
...
...
@@ -56,6 +59,40 @@
<table
id=
"products_table"
class=
"display"
cellspacing=
"0"
width=
"100%"
></table>
</div>
</div>
<div
id=
"orders_creation_area"
>
<div
class=
"add_product_container"
></div>
<button
type=
"button"
class=
'btn--primary'
id=
"create_orders"
style=
"display:none;"
>
Générer les commandes
</button>
</div>
</div>
<div
id=
"orders_created"
class=
"page_content"
style=
"display:none;"
>
<div
id=
"back_to_order_selection_from_orders_created"
>
<button
type=
"button"
class=
"btn--danger"
><i
class=
"fas fa-arrow-left"
></i>
Retour
</button>
</div>
<div
class=
"order_created_header txtcenter"
>
<h2>
Commandes créées !
</h2>
</div>
<div
class=
"txtcenter"
>
Livraison prévue le :
<span
id=
"recap_delivery_date"
>
XX/XX/XX
</span>
</div>
<div
id=
"created_orders_area"
></div>
<br/><br/><hr/><br/>
<div
class=
"mail_example_container"
>
<p
class=
"mail_type_text"
>
Mail type :
</p>
<div
class=
"mail_example"
>
Objet : Cde Cagette JJ/MM
<br/>
<br/>
Bonjour XXXXXXX,
<br/>
<br/>
Voici la commande de La Cagette pour le XX/XX/XX.
<br/>
<br/>
Merci d'avance,
<br/>
Bonne journée
</div>
</div>
</div>
<div
id=
"templates"
style=
"display:none;"
>
...
...
@@ -74,6 +111,19 @@
</div>
</div>
<div
id=
"new_order_item_template"
>
<div
class=
"new_order_item"
>
<h3
class=
"new_order_supplier_name"
></h3>
<h3
class=
"new_order_po"
></h3>
<div
class=
'download_order_file'
>
<i
class=
"fas fa-spinner fa-spin download_order_file_loading"
></i>
<a
class=
'btn--success download_order_file_button'
style=
"display:none;"
href=
"#"
>
Télécharger le fichier de commande
</a>
</div>
</div>
</div>
<div
id=
"modal_order_access"
>
<h3>
Attention !
</h3>
<br/>
...
...
@@ -126,6 +176,15 @@
<p>
Êtez-vous sûr ?
</p>
<hr/>
</div>
<div
id=
"modal_create_order"
>
<h3>
Attention !
</h3>
<p>
Vous vous apprêtez à générer les commandes à partir des données rentrées dans le tableau.
</p>
<p>
Êtez-vous sûr ?
</p>
<hr/>
</div>
</div>
</div>
...
...
@@ -134,6 +193,7 @@
<script
type=
"text/javascript"
>
var
couchdb_dbname
=
'{{db}}'
;
var
couchdb_server
=
'{{couchdb_server}}'
+
couchdb_dbname
;
var
odoo_server
=
'{{odoo_server}}'
;
</script>
<script
src=
"{% static "
js
/
all_common
.
js
"
%}?
v=
"></script>
<script type="
text
/
javascript
"
src=
"{% static 'js/orders_helper.js' %}?v="
></script>
...
...
This diff is collapsed.
Click to expand it.
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