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
d4e58ed9
Commit
d4e58ed9
authored
Mar 10, 2022
by
Etienne Freiss
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'dev_cooperatic' into 2251-shift-screen-associate
parents
fe9266d5
6aa05fdd
Pipeline
#1916
passed with stage
in 1 minute 31 seconds
Changes
9
Pipelines
1
Show whitespace changes
Inline
Side-by-side
Showing
9 changed files
with
155 additions
and
79 deletions
+155
-79
models.py
members/models.py
+4
-1
inscriptions.css
members/static/css/inscriptions.css
+3
-0
inscriptions.js
members/static/js/inscriptions.js
+1
-1
members-space-shifts-exchange.css
members_space/static/css/members-space-shifts-exchange.css
+13
-0
members-space-shifts-exchange.js
members_space/static/js/members-space-shifts-exchange.js
+13
-7
orders_helper.js
orders/static/js/orders_helper.js
+110
-67
views.py
shifts/views.py
+6
-0
inscriptions.html
templates/members/inscriptions.html
+1
-1
index.html
templates/members_space/index.html
+4
-2
No files found.
members/models.py
View file @
d4e58ed9
...
...
@@ -775,9 +775,12 @@ class CagetteMember(models.Model):
cond
=
[[
'name'
,
'ilike'
,
str
(
key
)]]
cond
.
append
(
'|'
)
cond
.
append
([
'is_member'
,
'='
,
True
])
if
search_type
!=
'members'
:
cond
.
append
([
'is_associated_people'
,
'='
,
True
])
else
:
cond
.
append
([
'is_associated_people'
,
'='
,
False
])
# cond.append(['cooperative_state', '!=', 'unsubscribed'])
if
search_type
==
"full"
:
if
search_type
==
"full"
or
search_type
==
'members'
:
fields
=
CagetteMember
.
m_default_fields
if
not
shift_id
is
None
:
CagetteMember
.
m_default_fields
.
append
(
'tmpl_reg_line_ids'
)
...
...
members/static/css/inscriptions.css
View file @
d4e58ed9
...
...
@@ -23,6 +23,9 @@
[
data-week
=
"4"
]
{
border
:
2px
#eed000
solid
;}
#new_coop
[
name
=
"email"
]
{
width
:
25em
;}
#new_coop
{
max-width
:
75%
;
}
#mail_generation
{
position
:
absolute
;
bottom
:
30px
;}
#sex
{
padding
:
0
;}
...
...
members/static/js/inscriptions.js
View file @
d4e58ed9
...
...
@@ -689,7 +689,7 @@ $(document).ready(function() {
if
(
search_str
)
{
$
.
ajax
({
url
:
'/members/search/'
+
search_str
,
url
:
'/members/search/'
+
search_str
+
"?search_type=members"
,
dataType
:
'json'
,
success
:
function
(
data
)
{
members_search_results
=
[];
...
...
members_space/static/css/members-space-shifts-exchange.css
View file @
d4e58ed9
...
...
@@ -217,6 +217,19 @@ td{
color
:
white
;
}
.fc-event.shift_booked_makeup
{
background-color
:
#f0ad4e
;
cursor
:
auto
;
border-color
:
#f0ad4e
;
}
.fc-event.shift_booked_makeup
td
{
--fc-list-event-hover-bg-color
:
#f0ad4e
;
}
.fc-list-event.shift_booked_makeup
{
color
:
white
;
}
#calendar
.fc-list-table
{
table-layout
:
auto
;
}
...
...
members_space/static/js/members-space-shifts-exchange.js
View file @
d4e58ed9
...
...
@@ -116,17 +116,17 @@ function add_or_change_shift(new_shift_id) {
closeModal
();
selected_shift
=
null
;
if
(
error
.
status
===
400
&&
error
.
msg
===
"Old service in less than 24hours."
)
{
if
(
error
.
status
===
400
&&
'msg'
in
error
.
responseJSON
&&
error
.
responseJSON
.
msg
===
"Old service in less than 24hours."
)
{
alert
(
`Désolé ! Le service que tu souhaites échanger démarre dans moins de 24h. `
+
`Afin de faciliter la logistique des services, il n'est plus possible de l'échanger. `
+
`Si tu ne peux vraiment pas venir, tu seras noté.e absent.e à ton service. `
+
`Tu devras alors sélectionner un service de rattrapage sur ton espace membre.`
);
}
else
if
(
error
.
status
===
500
&&
error
.
msg
===
"Fail to create shift"
)
{
}
else
if
(
error
.
status
===
500
&&
'msg'
in
error
.
responseJSON
&&
error
.
responseJSON
.
msg
===
"Fail to create shift"
)
{
// TODO differentiate error cases!
alert
(
`Une erreur est survenue. `
+
`Il est néanmoins possible que la requête ait abouti, `
+
`veuillez patienter quelques secondes puis vérifier vos services enregistrés.`
);
}
else
if
(
error
.
status
===
400
&&
error
.
msg
===
"Bad arguments"
)
{
}
else
if
(
error
.
status
===
400
&&
'msg'
in
error
.
responseJSON
&&
error
.
responseJSON
.
msg
===
"Bad arguments"
)
{
alert
(
`Une erreur est survenue. `
+
`Il est néanmoins possible que la requête ait abouti, `
+
`veuillez patienter quelques secondes puis vérifier vos services enregistrés.`
);
...
...
@@ -306,17 +306,23 @@ function init_shifts_list() {
shift_line_template
.
find
(
".shift_line_time"
).
text
(
datetime_shift_start
.
toLocaleTimeString
(
"fr-fr"
,
time_options
));
// Disable or not
if
(
!
can_exchange_shifts
()
&&
block_actions_for_attached_people
===
"True"
)
{
shift_line_template
.
find
(
".selectable_shift_line"
).
removeClass
(
"btn--primary"
);
shift_line_template
.
find
(
".selectable_shift_line"
).
removeClass
(
"btn"
);
shift_line_template
.
find
(
".selectable_shift_line"
).
removeClass
(
"btn--warning"
);
if
(
!
can_exchange_shifts
()
&&
block_actions_for_attached_people
===
"True"
)
{
shift_line_template
.
find
(
".selectable_shift_line"
).
addClass
(
"btn"
);
shift_line_template
.
find
(
".checkbox"
).
prop
(
"disabled"
,
"disabled"
);
}
else
{
shift_line_template
.
find
(
".selectable_shift_line"
).
removeClass
(
"btn"
);
if
(
shift
.
is_makeup
==
true
)
{
shift_line_template
.
find
(
".selectable_shift_line"
).
addClass
(
"btn--warning"
);
shift_line_template
.
find
(
".checkbox"
).
prop
(
"disabled"
,
false
);
shift_line_template
.
find
(
".checkbox"
).
prop
(
"value"
,
shift
.
id
);
}
else
{
shift_line_template
.
find
(
".selectable_shift_line"
).
addClass
(
"btn--primary"
);
shift_line_template
.
find
(
".checkbox"
).
prop
(
"disabled"
,
false
);
shift_line_template
.
find
(
".checkbox"
).
prop
(
"value"
,
shift
.
id
);
}
}
// Set assign shift button
if
(
partner_data
.
associated_partner_id
===
"False"
&&
partner_data
.
parent_id
===
"False"
)
{
shift_line_template
.
find
(
'.affect_associate_registered'
).
hide
();
...
...
@@ -531,7 +537,7 @@ function init_calendar_page() {
hiddenDays
:
hidden_days
,
events
:
'/shifts/get_list_shift_calendar/'
+
partner_data
.
concerned_partner_id
,
eventClick
:
function
(
info
)
{
if
(
!
$
(
info
.
el
).
hasClass
(
"shift_booked"
))
{
if
(
!
$
(
info
.
el
).
hasClass
(
"shift_booked"
)
&&
!
$
(
info
.
el
).
hasClass
(
"shift_booked_makeup"
)
)
{
const
new_shift_id
=
info
.
event
.
id
;
// Set new shift
...
...
orders/static/js/orders_helper.js
View file @
d4e58ed9
...
...
@@ -9,7 +9,8 @@ var suppliers_list = [],
new_product_supplier_association
=
{
package_qty
:
null
,
price
:
null
};
},
qties_values
=
{};
var
dbc
=
null
,
sync
=
null
,
...
...
@@ -30,6 +31,10 @@ var dbc = null,
var
clicked_order_pill
=
null
;
let
userAgent
=
navigator
.
userAgent
;
var
timerId
;
/* - UTILS */
...
...
@@ -124,12 +129,74 @@ function debounceFunction(func, delay = 1000) {
timerId
=
setTimeout
(
func
,
delay
);
}
/* - PRODUCTS */
var
process_new_product_qty
=
function
(
input
)
{
// Remove line coloring on input blur
const
row
=
$
(
input
).
closest
(
'tr'
);
row
.
removeClass
(
'focused_line'
);
let
val
=
(
$
(
input
).
val
()
==
''
)
?
0
:
$
(
input
).
val
();
const
id_split
=
$
(
input
).
attr
(
'id'
)
.
split
(
'_'
);
const
prod_id
=
id_split
[
1
];
const
supplier_id
=
id_split
[
3
];
if
(
val
==
-
1
)
{
let
modal_end_supplier_product_association
=
$
(
'#templates #modal_end_supplier_product_association'
);
const
product
=
products
.
find
(
p
=>
p
.
id
==
prod_id
);
modal_end_supplier_product_association
.
find
(
".product_name"
).
text
(
product
.
name
);
const
supplier
=
selected_suppliers
.
find
(
s
=>
s
.
id
==
supplier_id
);
modal_end_supplier_product_association
.
find
(
".supplier_name"
).
text
(
supplier
.
display_name
);
openModal
(
modal_end_supplier_product_association
.
html
(),
()
=>
{
if
(
is_time_to
(
'validate_end_supplier_product_association'
))
{
end_supplier_product_association
(
product
,
supplier
);
}
},
'Valider'
,
false
,
true
,
()
=>
{
// Reset value in input on cancel
const
psi
=
product
.
suppliersinfo
.
find
(
psi_item
=>
psi_item
.
supplier_id
==
supplier_id
);
$
(
input
).
val
(
psi
.
qty
);
}
);
}
else
{
val
=
parseFloat
(
val
);
// If value is a number
if
(
!
isNaN
(
val
))
{
// Save value
save_product_supplier_qty
(
prod_id
,
supplier_id
,
val
);
// Update row
const
product
=
products
.
find
(
p
=>
p
.
id
==
prod_id
);
const
new_row_data
=
prepare_datatable_data
([
product
.
id
])[
0
];
products_table
.
row
(
$
(
input
).
closest
(
'tr'
)).
data
(
new_row_data
)
.
draw
();
debounceFunction
(
update_cdb_order
);
display_total_values
();
}
else
{
$
(
input
).
val
(
''
);
}
}
};
/**
* Add a product.
*
* @returns -1 if validation failed, 0 otherwise
*/
function
add_product
()
{
const
user_input
=
$
(
"#product_input"
).
val
();
...
...
@@ -191,7 +258,13 @@ function add_product() {
return
0
;
}
function
compute_purchase_qty_for_coverage
(
product
,
coeff
,
stock
,
incoming_qty
,
daily_conso
,
days
)
{
let
purchase_qty_for_coverage
=
null
;
let
purchase_qty_for_coverage
=
0
,
purchase_package_qty_for_coverage
=
0
;
if
(
stock
==
0
&&
daily_conso
==
0
)
{
purchase_package_qty_for_coverage
=
1
;
}
else
{
purchase_qty_for_coverage
=
days
*
daily_conso
-
stock
-
incoming_qty
+
product
.
minimal_stock
;
purchase_qty_for_coverage
=
(
purchase_qty_for_coverage
<
0
)
?
0
:
purchase_qty_for_coverage
;
...
...
@@ -201,6 +274,7 @@ function compute_purchase_qty_for_coverage(product, coeff, stock, incoming_qty,
if
(
coeff
!=
1
)
{
purchase_package_qty_for_coverage
*=
coeff
;
}
}
// return Round up to unit for all products
return
Math
.
ceil
(
purchase_package_qty_for_coverage
);
}
...
...
@@ -217,6 +291,7 @@ function compute_and_affect_product_supplier_quantities(coeff, days) {
const
stock
=
product
.
qty_available
;
const
incoming_qty
=
product
.
incoming_qty
;
const
daily_conso
=
product
.
daily_conso
;
purchase_package_qty_for_coverage
=
compute_purchase_qty_for_coverage
(
product
,
coeff
,
stock
,
incoming_qty
,
daily_conso
,
days
);
// Set qty to purchase for first supplier only
products
[
key
].
suppliersinfo
[
0
].
qty
=
purchase_package_qty_for_coverage
;
...
...
@@ -234,6 +309,7 @@ function compute_products_coverage_qties() {
return
new
Promise
((
resolve
)
=>
{
const
pc_adjust
=
$
(
'#percent_adjust_input'
).
val
();
let
coeff
=
1
;
if
(
!
isNaN
(
parseFloat
(
pc_adjust
)))
{
coeff
=
(
1
+
parseFloat
(
pc_adjust
)
/
100
);
}
...
...
@@ -249,7 +325,7 @@ function compute_products_coverage_qties() {
step
=
1
;
//Let's compute the nearst amount, by changing days quantity
while
(
go_on
==
true
&&
iter
<
max_iter
)
{
while
(
go_on
==
true
&&
iter
<
max_iter
)
{
order_total_value
=
0
;
compute_and_affect_product_supplier_quantities
(
coeff
,
days
);
_compute_total_values_by_supplier
();
...
...
@@ -1674,68 +1750,11 @@ function display_products(params) {
row
.
addClass
(
'focused_line'
);
});
// Manage data on inputs blur
$
(
'#products_table'
).
on
(
'blur'
,
'tbody td .product_qty_input'
,
function
()
{
// Remove line coloring on input blur
const
row
=
$
(
this
).
closest
(
'tr'
);
row
.
removeClass
(
'focused_line'
);
let
val
=
(
$
(
this
).
val
()
==
''
)
?
0
:
$
(
this
).
val
();
const
id_split
=
$
(
this
).
attr
(
'id'
)
.
split
(
'_'
);
const
prod_id
=
id_split
[
1
];
const
supplier_id
=
id_split
[
3
];
if
(
val
==
-
1
)
{
let
modal_end_supplier_product_association
=
$
(
'#templates #modal_end_supplier_product_association'
);
const
product
=
products
.
find
(
p
=>
p
.
id
==
prod_id
);
modal_end_supplier_product_association
.
find
(
".product_name"
).
text
(
product
.
name
);
const
supplier
=
selected_suppliers
.
find
(
s
=>
s
.
id
==
supplier_id
);
modal_end_supplier_product_association
.
find
(
".supplier_name"
).
text
(
supplier
.
display_name
);
openModal
(
modal_end_supplier_product_association
.
html
(),
()
=>
{
if
(
is_time_to
(
'validate_end_supplier_product_association'
))
{
end_supplier_product_association
(
product
,
supplier
);
}
},
'Valider'
,
false
,
true
,
()
=>
{
// Reset value in input on cancel
const
psi
=
product
.
suppliersinfo
.
find
(
psi_item
=>
psi_item
.
supplier_id
==
supplier_id
);
$
(
this
).
val
(
psi
.
qty
);
}
);
}
else
{
val
=
parseFloat
(
val
);
// If value is a number
if
(
!
isNaN
(
val
))
{
// Save value
save_product_supplier_qty
(
prod_id
,
supplier_id
,
val
);
// Update row
const
product
=
products
.
find
(
p
=>
p
.
id
==
prod_id
);
const
new_row_data
=
prepare_datatable_data
([
product
.
id
])[
0
];
products_table
.
row
(
$
(
this
).
closest
(
'tr'
)).
data
(
new_row_data
)
.
draw
();
debounceFunction
(
update_cdb_order
);
display_total_values
();
}
else
{
$
(
this
).
val
(
''
);
}
}
// Manage data on inputs blur
$
(
'#products_table'
)
.
on
(
'blur'
,
'tbody td .product_qty_input'
,
function
()
{
process_new_product_qty
(
this
);
})
.
on
(
'keypress'
,
'tbody td .product_qty_input'
,
function
(
e
)
{
// Validate on Enter pressed
...
...
@@ -2254,12 +2273,12 @@ $(document).ready(function() {
.
then
(()
=>
{
debounceFunction
(
update_cdb_order
);
update_main_screen
();
})
});
}
else
{
$
(
"#coverage_days_input"
).
val
(
order_doc
.
coverage_days
||
''
);
$
(
'#targeted_amount_input'
).
val
(
order_doc
.
targeted_amount
||
''
);
alert
(
"Ni le nombre de jours de couverture, ni le montant à atteindre sont correctement renseignés"
)
alert
(
"Ni le nombre de jours de couverture, ni le montant à atteindre sont correctement renseignés"
)
;
}
}
...
...
@@ -2319,7 +2338,7 @@ $(document).ready(function() {
update_main_screen
();
debounceFunction
(
update_cdb_order
);
closeModal
();
})
});
});
}
...
...
@@ -2590,6 +2609,30 @@ $(document).ready(function() {
panel
.
style
.
display
=
"block"
;
}
});
if
(
/Firefox
\/
/
.
exec
(
userAgent
))
{
// needed to prevent bug using number input arrow to change quantity (https://bugzilla.mozilla.org/show_bug.cgi?id=1012818)
// Have to capture mousedown and mouseup events, instead of using only click event
// Indeed, capturing click only remove the ability to click to have focus on the input to type a number.
$
(
document
).
on
(
"mousedown"
,
'[type="number"]'
,
function
()
{
const
clicked
=
this
;
qties_values
[
$
(
clicked
).
attr
(
'id'
)]
=
$
(
clicked
).
val
();
});
$
(
document
).
on
(
"mouseup"
,
'[type="number"]'
,
function
()
{
const
clicked
=
this
;
try
{
if
(
$
(
clicked
).
val
()
!=
qties_values
[
$
(
clicked
).
attr
(
'id'
)])
{
process_new_product_qty
(
clicked
);
}
}
catch
(
err
)
{
console
.
log
(
err
);
}
});
}
}
else
{
$
(
'#not_connected_content'
).
show
();
}
...
...
shifts/views.py
View file @
d4e58ed9
...
...
@@ -101,8 +101,11 @@ def get_list_shift_calendar(request, partner_id):
use_new_members_space
=
getattr
(
settings
,
'USE_NEW_MEMBERS_SPACE'
,
False
)
listRegisterPartner
=
[]
listMakeUpShift
=
[]
for
v
in
registerPartner
:
listRegisterPartner
.
append
(
v
[
'id'
])
if
v
[
'is_makeup'
]:
listMakeUpShift
.
append
(
v
[
'id'
])
start
=
request
.
GET
.
get
(
'start'
)
end
=
request
.
GET
.
get
(
'end'
)
...
...
@@ -136,6 +139,9 @@ def get_list_shift_calendar(request, partner_id):
if
len
(
l
)
>
0
:
if
use_new_members_space
is
True
:
if
set
(
value
[
'registration_ids'
])
&
set
(
listRegisterPartner
)
&
set
(
listMakeUpShift
):
event
[
"classNames"
]
=
[
"shift_booked_makeup"
]
else
:
event
[
"classNames"
]
=
[
"shift_booked"
]
else
:
event
[
"className"
]
=
"shift_booked"
...
...
templates/members/inscriptions.html
View file @
d4e58ed9
...
...
@@ -37,7 +37,7 @@
<section
class=
"center"
id=
"new_coop"
>
<div
class=
"grid-1"
>
<div
class=
""
>
<div
class=
"
item-center
"
>
<h2
class=
"title"
>
NOUVEAU MEMBRE
</h2>
...
...
templates/members_space/index.html
View file @
d4e58ed9
...
...
@@ -81,10 +81,12 @@
<div
id=
"calendar_explaination_template"
>
<h4>
Légende du calendrier
</h4>
<a
class=
"example-event fc-daygrid-event fc-daygrid-block-event fc-h-event fc-event fc-event-start fc-event-end fc-event-future shift_booked"
><div
class=
"fc-event-main"
><div
class=
"fc-event-main-frame"
><div
class=
"fc-event-time"
>
06:00
</div><div
class=
"fc-event-title-container"
><div
class=
"fc-event-title fc-sticky"
>
- 9/12
</div></div></div></div></a>
<p>
Un service colorié en noir : je suis déjà inscrit.e à ce service.
</p>
<a
class=
"example-event fc-daygrid-event fc-daygrid-block-event fc-h-event fc-event fc-event-start fc-event-end fc-event-future shift_less_alf"
><div
class=
"fc-event-main"
><div
class=
"fc-event-main-frame"
><div
class=
"fc-event-time"
>
10:45
</div><div
class=
"fc-event-title-container"
><div
class=
"fc-event-title fc-sticky"
>
- 3/12
</div></div></div></div></a>
<p>
Un service colorié en bleu : je peux m'inscrire à ce service.
</p>
<a
class=
"example-event fc-daygrid-event fc-daygrid-block-event fc-h-event fc-event fc-event-start fc-event-end fc-event-future shift_booked"
><div
class=
"fc-event-main"
><div
class=
"fc-event-main-frame"
><div
class=
"fc-event-time"
>
06:00
</div><div
class=
"fc-event-title-container"
><div
class=
"fc-event-title fc-sticky"
>
- 9/12
</div></div></div></div></a>
<p>
Un service colorié en noir : je suis déjà inscrit.e à ce service.
</p>
<a
class=
"example-event fc-daygrid-event fc-daygrid-block-event fc-h-event fc-event fc-event-start fc-event-end fc-event-future shift_booked_makeup"
><div
class=
"fc-event-main"
><div
class=
"fc-event-main-frame"
><div
class=
"fc-event-time"
>
13:30
</div><div
class=
"fc-event-title-container"
><div
class=
"fc-event-title fc-sticky"
>
- 7/12
</div></div></div></div></a>
<p>
Un service colorié en orange : je suis inscrit.e à un rattrapage sur ce service.
</p>
<p>
3/12
<i
class=
"arrow_explanation_numbers fas fa-arrow-right"
></i>
il y a déjà 3 places réservées à ce service sur 12 disponibles.
<b>
Plus le chiffre de gauche est petit, plus on a besoin de coopérateurs.rices à ce service !
</b></p>
</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