Commit e5493c3e by Yvon Kerdoncuff

Merge branch 'dev_cooperatic' into 'supercafoutch_prod'

MEP Supercafoutch 9 juin 2024

See merge request !275
parents 80e725a9 8da39cf9
Pipeline #3738 failed with stage
in 48 seconds
"""Company specific data values."""
MAG_NAME = ''
COMPANY_NAME = 'GRAOUCOOP'
OFFICE_NAME = ''
EMAIL_DOMAIN = 'graoucoop.fr'
COMPANY_LOGO = 'https://graoucoop.fr/wp-content/uploads/2023/02/logo-graoucoop-horiz-og.png'
# OPEN_ON_SUNDAY = True
MAX_BEGIN_HOUR = '19:00'
WELCOME_ENTRANCE_MSG = 'Bienvenue à Graoucoop !'
WELCOME_MAIL_SUBJECT = 'Dernière étape de votre inscription à Graoucoop.'
WELCOME_MAIL_TEMPLATE = 'members/graoucoop/bienvenue.html'
TOOLS_SERVER = 'https://outils.graoucoop.fr'
DAV_PATH = '/shared_dir/dav/'
ADMIN_IDS = [1,38]
BRINKS_MUST_IDENTIFY = True
CAP_JOURNAL_ID = 9
CAP_APPELE_NON_VERSE_ACCOUNT_ID = 529
CAP_APPELE_VERSE_ACCOUNT_ID = 8
CAP_INVOICE_LINE_ACCOUNT_ID = 7
FUNDRAISING_CAT_ID = 1
UNITE_UOM_ID = 1
PARTS_A_PRODUCT_ID = 5
PARTS_B_PRODUCT_ID = 6
PARTS_C_PRODUCT_ID = 7
PARTS_PRICE_UNIT = 10.0
PARTS_A_PRICE_UNIT = PARTS_PRICE_UNIT
COOP_BARCODE_RULE_ID = 11
CHECK_PAYMENT_ID = 97
VIREMENT_PAYMENT_ID = 98
CASH_PAYMENT_ID = 18
#CB_PAYMENT_ID = 15
#HELLO_ASSO_PAYMENT_ID = 29
STOCK_LOC_ID = 12
CATEG_FRUIT = 151
CATEG_LEGUME = 152
VRAC_CATEGS = [166, 167, 174, 179]
#EXPORT_POS_CAT_FOR_SCALES = True
FLV_CSV_NB = 2
COEFF_MAG_ID = 1
RECEPTION_PDT_LABELS_FN = 'print_product_labels()'
RECEPTION_PDT_LABELS_TEXT = 'Cliquez sur ce bouton pour imprimer les étiquettes code-barres à coller sur les produits'
RECEPTION_PDT_LABELS_BTN_TEXT = 'Lancer l\'impression'
RECEPTION_SHELF_LABEL_PRINT = False
FIXED_BARCODE_PREFIX = '0490'
RECEPTION_ADD_ADMIN_MODE = True
RECEPTION_ADD_ALL_LEFT_IS_GOOD = True
RECEPTION_MERGE_ORDERS_PSWD='pass2makeApause'
DISPLAY_COL_AUTRES = False
RECEPTION_ADD_PRODUCTS_PSWD= 'pass2makeApause'
NO_BARCODE_MAIL_MSG = "contact@graoucoop.fr"
SUBSCRIPTION_PAYMENT_MEANINGS = [
{'code': 'cash', 'title': 'Espèces','journal_id': CASH_PAYMENT_ID},
{'code': 'ch', 'title': 'Chèque', 'journal_id': CHECK_PAYMENT_ID},
{'code': 'vir', 'title': 'Virement', 'journal_id': VIREMENT_PAYMENT_ID},
]
CAN_CREATE_BINOME = False
SUBSCRIPTION_NAME_SEP = ', '
CONCAT_NAME_ORDER = 'LF'
SUBSCRIPTION_ASK_FOR_SEX = True
WITH_WEBSITE_MENU = True
SUBSCRIPTION_ADD_STREET2 = True
SUBSCRIPTION_ADD_SECOND_PHONE = True
FORCE_HYPHEN_IN_SUBSCRIPTION_FIRSTNAME = False
ENTRANCE_EXTRA_BUTTONS_DISPLAY = False
ADMIN_BINOME_ACTIVE = False
SHOP_CAN_BUY = True
DELIVERY_CAN_BUY = True
SHOP_HEADER_IMG = 'https://graoucoop.fr/wp-content/uploads/2021/01/logo-graoucoop-horiz.png'
SHOP_OPENING = {'jeu.': [{'start': '15:45', 'end': '18:15'}, {'start': '18:30', 'end': '21:00'}],
'ven.': [{'start': '15:45', 'end': '18:15'}, {'start': '18:30', 'end': '21:00'}],
'sam.': [{'start': '10:15', 'end': '12:45'}, {'start': '13:00', 'end': '15:30'}]}
SHOP_SLOT_SIZE = 15 # minutes
SHOP_CATEGORIES = {
'epicerie': {'id': 75, 'label': 'Epicerie'},
'liquide': {'id': 96, 'label': 'Liquides'},
'produits_frais': {'id': 104, 'label': 'Frais'},
'surgeles': {'id': 115, 'label': 'Surgelés'},
'bazar': {'id': 122, 'label': 'Maison & Bazar'},
'droguerie': {'id': 127, 'label': 'Droguerie Hygiène'},
'parfumerie': {'id': 133, 'label': 'Parfumerie'}
}
ALLOW_NON_MEMBER_TO_CONNECT = True
EXCLUDE_SHOP_CATEGORIES=[]
DEFAULT_MAX_TIMESLOT_CARTS = 1
MIN_DELAY_FOR_SLOT = 0
HOURS_FOR_VALIDATION_SHOP = 2
SHOW_SUBSTITUTION_OPTION = False
CART_VALIDATION_BOTTOM_MSG = ""
SHOP_STOCK_WARNING = False
SHOP_BOTTOM_VALIDATION_MSG = 'Message personnalisable'
#SHOP_LIMIT_PRODUCTS = ['relatively_available', 'no_shelf']
#VALIDATION_ORDER_MAIL_TEMPLATE = 'shop/lgds_validation_mail.html'
EM_URL = ''
USE_NEW_MEMBERS_SPACE = True
USE_NEW_MEMBERS_SPACE = True
REMOVE_15_MINUTES_AT_SHIFT_END = False
CAN_ADD_SHIFT = True
COOP_CAN_CHANGE_SHIFT_TEMPLATE = True
SHIFT_EXCHANGE_DAYS_TO_HIDE = ''
SHIFT_INFO = """Un service est une plage de trois heures un jour en particulier, par exemple : le mardi 25/09/2018 à 13h15.
<br />A l'inverse, un créneau est une plage de trois heures régulière, par exemple, tous les mardi de semaine A à 13h15."""
PB_INSTRUCTIONS="""Si j'ai un problème, que je suis désinscrit, que je veux changer de créneaux ou quoi que ce soit, merci de se rendre au magasin"""
CALENDAR_NO_MORE_LINK = True
MEMBERS_SPACE_SHOW_UNDERSTAND_MY_STATUS = True
MEMBERS_SPACE_FAQ_TEMPLATE = 'members_space/graoucoop/faq.html'
MEMBERS_SPACE_UNDERSTAND_MY_STATUS_TEMPLATE = 'members_space/graoucoop/understand_my_status.html'
BRINKS_MUST_IDENTIFY = True
PROMOTE_SHELFS_IDS = []
DISCOUNT_SHELFS_IDS = []
FL_SHELFS = []
VRAC_SHELFS = []
ENTRANCE_FTOP_BUTTON_DISPLAY = False
#CUSTOM_CSS_FILES = {'all': ['common_lgds.css'],
# 'members': ['inscription_lgds.css']}
LOSSES_LOC_ID = 33
LOSSES_PICKING_TYPE_ID = 10
AUTOCONSO_LOC_ID = 27
AUTOCONSO_PICKING_TYPE_ID = 7
MEALS_LOC_ID = 36
MEALS_PICKING_TYPE_ID = 16
SUBSCRIPTION_ASK_FOR_SEX = True
"""Company specific data values."""
ODOO_PUBLIC_URL='https://odoo.lacagette-coop.fr'
MAG_NAME = 'Cleme'
OFFICE_NAME = ''
MAX_BEGIN_HOUR = '19:00'
COMPANY_CODE = 'lacagette'
COMPANY_NAME = 'La Cagette'
COMPANY_LOGO = 'https://lacagette-coop.fr/files/HeaderAccueil_image_accueil_opt3_20200208170224_20200208160306.jpg'
WELCOME_ENTRANCE_MSG = 'Bienvenue à La Cagette !'
WELCOME_MAIL_SUBJECT = 'Dernière étape de votre inscription à la Cagette.'
WELCOME_MAIL_TEMPLATE = 'members/bienvenue.html'
OPEN_ON_SUNDAY = True
ENTRANCE_WITH_LATE_MODE = True
BLOCK_SERVICE_EXCHANGE_24H_BEFORE = False
USE_NEW_MEMBERS_SPACE = True
ASSOCIATE_MEMBER_SHIFT = 430
BLOCK_ACTIONS_FOR_ATTACHED_PEOPLE = False
START_DATE_FOR_POINTS_HISTORY = "2021-07-01"
START_DATE_FOR_SHIFTS_HISTORY = "2021-07-01"
COMPANY_CODE = "lacagette"
AMNISTIE_DATE= "2021-11-24 23:00:00"
DEFAULT_SHIFT_TYPE = 'standard'
SHOW_FTOP_BUTTON = False
USE_STANDARD_SHIFT = True
# OPEN_ON_SUNDAY = True
FLV_CSV_NB = 6
FLV_CSV_NB = 4
CAP_JOURNAL_ID = 9
CAP_APPELE_NON_VERSE_ACCOUNT_ID = 529
......@@ -22,6 +38,7 @@ UNITE_UOM_ID = 1
PARTS_A_PRODUCT_ID = 1008
PARTS_A_PRICE_UNIT = 10.0
COOP_BARCODE_RULE_ID = 11
ASSOCIATE_BARCODE_RULE_ID = 12
CHECK_PAYMENT_ID = 8
CASH_PAYMENT_ID = 18
......@@ -53,23 +70,37 @@ SUBSCRIPTION_PAYMENT_MEANINGS = [{'code': 'cash', 'title': 'Espèces', 'journal_
{'code': 'ch', 'title': 'Chèque', 'journal_id': CHECK_PAYMENT_ID}]
EM_URL = ''
PREPA_ODOO_URL = "https://inscriptions.lacagette-coop.fr/members/prepa-odoo/"
RECEPTION_SHELF_LABEL_PRINT = True
RECEPTION_MERGE_ORDERS_PSWD = 'jpsrcp'
RECEPTION_ADD_PRODUCTS_PSWD = 'jpsrcp'
RECEPTION_UPDATE_QTY_PSWD = 'jpsrcp'
RECEPTION_PDT_LABELS_FN = 'print_product_labels()'
RECEPTION_PDT_LABELS_TEXT = 'Cliquez sur ce bouton pour imprimer les étiquettes code-barres à coller sur les produits'
RECEPTION_PDT_LABELS_BTN_TEXT = 'Lancer l\'impression'
FIXED_BARCODE_PREFIX = '0490'
RECEPTION_PB = "Ici, vous pouvez signaler toute anomalie lors d'une réception, les produits non commandés, cassés ou pourris. \
Merci d'indiquer un maximum d'informations, le nom du produit et son code barre."
DISPLAY_COL_AUTRES = False
RECEPTION_ADD_ALL_LEFT_IS_GOOD_QTIES = False
RECEPTION_ADD_ALL_LEFT_IS_GOOD_PRICES = True
NO_BARCODE_MAIL_SUBJECT = " Articles sans codebarre de la commande : {}"
NO_BARCODE_MAIL_MSG = """
Bonjour {0},
Vous avez crée la commande {1}, le {2}, pour {3}
Voici la liste des codes barres qui manquent :
"""
DAV_PATH = '/shared_dir/dav/'
TOOLS_SERVER = 'https://outils.lacagette-coop.fr'
ADMIN_IDS = [13]
BRINKS_MUST_IDENTIFY = False
BRINKS_MUST_IDENTIFY = True
SHOP_CAN_BUY = False
# SHOP_OPENING = {'mar.': [{'start': '10:30', 'end': '14:00'}, {'start': '15:30', 'end': '20:00'}],
......@@ -100,54 +131,42 @@ DISCOUNT_SHELFS_IDS = [74]
FL_SHELFS = [16, 17, 18]
VRAC_SHELFS = [20, 38]
SHELFS_TO_BE_AHEAD_IN_SELECT_LIST = [90,74]
SHIFT_EXCHANGE_DAYS_TO_HIDE = '0'
SHIFT_INFO = """A la cagette, un service est une plage de trois heures un jour en particulier, par exemple : le mardi 25/09/2018 à 13h15.
<br />A l'inverse, un créneau est une plage de trois heures régulière, par exemple, tous les mardi de semaine A à 13h15."""
PB_INSTRUCTIONS = """Si j'ai un problème, que je suis désinscrit, que je veux changer de créneaux ou quoi que ce soit, merci de vous rendre dans la section \"J'ai un problème\" sur le site web de <a href=\"https://lacagette-coop.fr/?MonEspaceMembre\">La Cagette</a>"""
#Regex stricte pour les numéros de téléphone français sur 10 chiffres
#et permissive pour les numéros commençant par + ou 00
INPUT_PHONE_PATTERN = "((\+|00)\d{5,30})|\d{10}"
ENTRANCE_COME_FOR_SHOPING_MSG = "Hey coucou toi ! Cet été nous sommes plus de <strong>1000 acheteur·euses</strong> pour seulement <strong>300 coopérateur·rice·s</strong> en service. <br />Tu fais tes courses à La Cagette cet été ?<br/> Inscris-toi sur ton espace membre !"
ENTRANCE_EXTRA_BUTTONS_DISPLAY = False
ENTRANCE_EASY_SHIFT_VALIDATE = True
ENTRANCE_MISSED_SHIFT_BEGIN_MSG = """La période pendant laquelle il est possible de s'enregistrer est close.<br />
Merci de remplir le formulaire <em>"arrivé·e en retard"</em> <br/>
que vous trouverez <em>sur le site internet de La Cagette</em>
dans la rubrique<br />
"Espace Membre" > "J\'ai un problème ou une demande".<br/>
Le bureau des membres traitera votre demande !'
ENTRANCE_MISSED_SHIFT_BEGIN_MSG = """La période pendant laquelle il est possible de s'enregistrer est close.<br/>
Pour tout problème ou demande vous pouvez contacter le Bureau des Membres via les formulaires depuis votre espace membre.
"""
ENTRANCE_EASY_SHIFT_VALIDATE_MSG = """Si vous faites un service dans un comité, merci de <br/>
valider votre présence en cherchant<br/>
votre nom ou numéro ci-dessous
"""
PREPA_ODOO_URL = '[...]'
ENTRANCE_VALIDATE_PRESENCE_MESSAGE = """
<div class="explanations">
Ta présence a bien été validée ! Merci de te diriger au fond du magasin pour le lancement du créneau !
</div>
Ton prochain service <span class="service_verb">est prévu</span> le <span class="next_shift"></span>
"""
MINIMUM_SECONDS_BETWEEN_TWO_COMITEE_VALIDATION = 1
# Members space / shifts
UNSUBSCRIBED_FORM_LINK = 'https://docs.google.com/forms/d/e/1FAIpQLScWcpls-ruYIp7HdrjRF1B1TyuzdqhvlUIcUWynbEujfj3dTg/viewform'
UNSUBSCRIBED_MSG = 'Vous êtes désincrit·e, merci de remplir <a href="https://docs.google.com/forms/d/e/1FAIpQLSfPiC2PkSem9x_B5M7LKpoFNLDIz0k0V5I2W3Mra9AnqnQunw/viewform">ce formulaire</a> pour vous réinscrire sur un créneau.<br />Vous pouvez également contacter le Bureau des Membres en remplissant <a href="https://docs.google.com/forms/d/e/1FAIpQLSeZP0m5-EXPVJxEKJk6EjwSyZJtnbiGdYDuAeFI3ENsHAOikg/viewform">ce formulaire</a>'
UNSUBSCRIBED_FORM_LINK = 'https://docs.google.com/forms/d/e/1FAIpQLScWcpls-ruYIp7HdrjRF1B1TyuzdqhvlUIcUWynbEujfj3dTg/viewform'
CONFIRME_PRESENT_BTN = 'Clique ici pour valider ta présence'
BLOCK_ACTIONS_FOR_ATTACHED_PEOPLE = False
RECEPTION_PB = "Ici, vous pouvez signaler toute anomalie lors d'une réception, les produits non commandés, cassés ou pourris. \
Merci d'indiquer un maximum d'informations, le nom du produit et son code barre. \
Dans le cas de produits déteriorés, merci d'envoyer une photo avec votre téléphone à [Adresse_email]"
# display or not column "Autres" in reception process
DISPLAY_COL_AUTRES = False
# Should block service exchange if old service is happening in less than 24h
BLOCK_SERVICE_EXCHANGE_24H_BEFORE = True
# URL to the metabase dashboard for orders helper
ORDERS_HELPER_METABASE_URL = "url_meta_base"
# New members space
USE_NEW_MEMBERS_SPACE = True
START_DATE_FOR_SHIFTS_HISTORY = "2018-01-01"
AMNISTIE_DATE= "2021-11-24 00:00:00"
ORDERS_HELPER_METABASE_URL = "https://metabase.lacagette-coop.fr/dashboard/16"
# BDM Admin
BDM_SHOW_FTOP_BUTTON = True
# Entree
MINIMUM_SECONDS_BETWEEN_TWO_COMITEE_VALIDATION = 0
SUBSCRIPTION_ASK_FOR_SEX = True
\ No newline at end of file
SUBSCRIPTION_ASK_FOR_SEX = True
......@@ -129,7 +129,9 @@ SHIFT_INFO = """Un service est une plage de trois heures un jour en particulier
PB_INSTRUCTIONS = """Si j'ai un problème, que je suis désinscrit, que je veux changer de créneaux ou quoi que ce soit, merci de ..."""
ENTRANCE_COME_FOR_SHOPING_MSG = "Bienvenue dans ton magasin !"
INPUT_PHONE_PATTERN = "^(((\+33(-| )\d{1})|\d{2})(\.| )\d{2}(\.| )\d{2}(\.| )\d{2}(\.| )\d{2})|(0\d{9})$"
#Regex stricte pour les numéros de téléphone français sur 10 chiffres
#et permissive pour les numéros commençant par + ou 00
INPUT_PHONE_PATTERN = "((\+|00)\d{5,30})|\d{10}"
CONFIRME_PRESENT_BTN = 'Clique ici pour valider ta présence'
ENTRANCE_WITH_LATE_MODE = True
# Members space / shifts
......@@ -161,4 +163,6 @@ AUTOCONSO_LOC_ID = 27
AUTOCONSO_PICKING_TYPE_ID = 7
SUBSCRIPTION_ASK_FOR_SEX = True
SUBSCRIPTION_ASK_FOR_JOB = True
\ No newline at end of file
SUBSCRIPTION_ASK_FOR_JOB = True
ALLOW_BOTH_AS_ANSWER_TO_WHO_IS_COMING_TO_SHIFT = False
\ No newline at end of file
......@@ -35,6 +35,40 @@ class CagetteEnvelops(models.Model):
ids.append(key)
return ids
def get_related_invoice(self, data):
invoice = None
message = ""
# Get specific invoice if id is given
if 'invoice_id' in data:
cond = [['id', '=', data['invoice_id']], ["number", "!=", False]]
else:
cond = [['partner_id', '=', data['partner_id']], ["number", "!=", False], ["residual_signed", ">", 0]]
fields = ['id', 'name', 'number', 'partner_id', 'residual_signed']
invoice_res = self.o_api.search_read('account.invoice', cond, fields,order="residual_signed DESC")
# Check if invoice exists
if len(invoice_res) > 0:
# Get first invoice for which amount being paid <= amount left to pay in invoice
for invoice_item in invoice_res:
if int(float(data['amount']) * 100) <= int(float(invoice_item['residual_signed']) * 100):
invoice = invoice_item
if invoice is None:
message = 'The amount is too high for the invoices found for this partner.'
if invoice is None and 'invoice_id' in data:
"""Because of a legacy bug,
some capital subscription recording processes
could save a wrong 0 amount invoice in envelop,
instead of the one with right amount.
So, let's retry without invoice_id"""
del data['invoice_id']
[invoice, message] = self.get_related_invoice(data)
# Can't fall into a loop since invoice_id key has been deleted
return [invoice, message]
def save_payment(self, data):
"""Save a partner payment"""
res = {
......@@ -43,35 +77,11 @@ class CagetteEnvelops(models.Model):
try:
# Get invoice
# Get specific invoice if id is given
if 'invoice_id' in data:
cond = [['id', '=', data['invoice_id']], ["number", "!=", False]]
else:
cond = [['partner_id', '=', data['partner_id']], ["number", "!=", False]]
fields = ['id', 'name', 'number', 'partner_id', 'residual_signed']
invoice_res = self.o_api.search_read('account.invoice', cond, fields)
# Check if invoice exists
if len(invoice_res) > 0:
invoice = None
# Get first invoice for which amount being paid <= amount left to pay in invoice
for invoice_item in invoice_res:
if int(float(data['amount']) * 100) <= int(float(invoice_item['residual_signed']) * 100):
invoice = invoice_item
if invoice is None:
res['error'] = 'The amount is too high for the invoices found for this partner.'
try:
# Got an error while logging...
coop_logger.error(res['error'] + ' : %s', str(data))
except Exception as e:
print(str(e))
return res
else:
res['error'] = 'No invoice found for this partner, can\'t create payment.'
coop_logger.error(res['error'] + ' : %s', str(data))
[invoice, message] = self.get_related_invoice(data)
if invoice is None:
if len(message) == 0:
message = 'No invoice found for this partner, can\'t create payment.'
res['error'] = message
return res
payment_journal_id = None
......@@ -97,7 +107,7 @@ class CagetteEnvelops(models.Model):
payment_id = self.o_api.create('account.payment', args)
except Exception as e:
res['error'] = repr(e)
coop_logger.error(res['error'] + ' : %s', str(args))
coop_logger.error(res['error'] + ": %s", str(args))
# Exception rises when odoo method returns nothing
marshal_none_error = 'cannot marshal None unless allow_none is enabled'
......@@ -196,8 +206,12 @@ class CagetteEnvelops(models.Model):
else:
# Get the oldest check envelops, limited by the number of checks
docs = []
for item in c_db.dbc.view('index/by_type_not_archive', key='ch', include_docs=True, limit=payment_data['checks_nb']):
docs.append(item.doc)
try:
for item in c_db.dbc.view('index/by_type_not_archive', key='ch', include_docs=True, limit=payment_data['checks_nb']):
docs.append(item.doc)
except:
# Exception raised if no envelop
pass
# If only 1 check to save
if int(payment_data['checks_nb']) == 1:
......
......@@ -226,7 +226,7 @@ function set_envelop_dom(envelop, envelop_name, envelop_content_id, envelop_inde
let search_str = modal.find('.search_member_input').val();
$.ajax({
url: '/members/search/' + search_str + "?search_type=short",
url: '/members/search/' + search_str + "?search_type=envelops",
dataType : 'json',
success: function(data) {
members_search_results = data.res;
......
......@@ -51,7 +51,7 @@ def archive_envelop(request):
}
coop_logger.error("Payment error : %s \n %s", str(data), str(e))
if res['done']:
if res['done'] is True:
# Immediately save a token than this payment has been saved
# If an error occurs, this payment won't be saved again
envelop['envelop_content'][partner_id]['payment_id'] = res['payment_id']
......
......@@ -126,7 +126,13 @@ default_msettings = {'msg_accueil': {'title': 'Message borne accueil',
'value': '',
'class': 'link',
'sort_order': 21
}
},
'on_picking_shift_template_msg': {
'title': 'Afficher une info à la sélection d\'un créneau (jour,heure) en respectant la syntaxe en exemple : lundi 14:00 Ici votre message',
'type': 'text',
'value': '',
'sort_order': 22
},
}
......@@ -296,6 +302,7 @@ def generate_base_and_barcode(request, member_id):
return response
def create_envelops(request):
"""Only used from manage_mess, which was a tempory fonctionality"""
res = {}
is_connected_user = CagetteUser.are_credentials_ok(request)
if is_connected_user is True:
......@@ -843,7 +850,9 @@ def create_pair(request):
# le suppléant a des rattrapages
if child_makeups + parent_makeups <=2:
# on transfert les rattrapages sur le parent
api.update("res.partner", [parent_id], {"makeups_to_do": parent['makeups_to_do'] + child['makeups_to_do']})
# Comme on annule les services du suppléant, on ajoute en makeup_to_do du titulaire les rattrapages choisis ou non du suppléant
api.update("res.partner", [parent_id], {"makeups_to_do": parent['makeups_to_do'] + child_makeups})
# On annule les rattrapages du child
api.update('res.partner', [child_id], {"makeups_to_do": 0})
......
......@@ -389,7 +389,7 @@ class CagetteMember(models.Model):
res = {}
# First, update couchdb data
c_db = CouchDB(arg_db='member')
shift_template = json.loads(post_data['shift_template'])
# shift_template = json.loads(post_data['shift_template'])
received_data = {'birthdate': post_data['birthdate'],
'city': post_data['city'],
'zip': post_data['zip'],
......@@ -573,11 +573,14 @@ class CagetteMember(models.Model):
# We add the associated member to the "associate" shift template so we can find them in Odoo
elif 'is_associated_people' not in post_data or 'is_associated_people' in post_data and 'parent_id' not in post_data:
# Create shift suscription if is not associated
shift_template = json.loads(post_data['shift_template'])
shift_t_id = shift_template['data']['id']
stype = shift_template['data']['type']
res['shift'] = \
m.create_coop_shift_subscription(shift_t_id, stype)
try:
shift_template = json.loads(post_data['shift_template'])
shift_t_id = shift_template['data']['id']
stype = shift_template['data']['type']
res['shift'] = \
m.create_coop_shift_subscription(shift_t_id, stype)
except Exception as no_shift_e:
coop_logger.error("Pas de créneau défini : %s \n %s", str(post_data), str(no_shift_e))
# m.add_first_point(stype) # Not needed anymore
# Update couchdb do with new data
......@@ -605,13 +608,11 @@ class CagetteMember(models.Model):
payment_data['checks'] = json.loads(post_data['checks'])
else:
payment_data['checks'] = []
if payment_data['payment_meaning'] == 'cash' or payment_data['payment_meaning'] == 'ch':
res['envelop'] = CagetteEnvelops().create_or_update_envelops(payment_data)
else:
p_data = {'partner_id': partner_id, 'type': payment_data['payment_meaning'], 'amount': post_data['shares_euros']}
res['envelop'] = CagetteEnvelops().save_payment(p_data)
# Send welcome mail
try:
api.execute('res.partner', 'send_welcome_email', [partner_id])
......@@ -805,12 +806,14 @@ class CagetteMember(models.Model):
cond = [['name', 'ilike', str(key)]]
cond.append('|')
cond.append(['is_member', '=', True])
if search_type != 'members':
if search_type != 'members' and search_type != 'envelops':
cond.append(['is_associated_people', '=', True])
else:
cond.append(['is_associated_people', '=', False])
cond.append(['cooperative_state', '!=', 'associated'])
if search_type != 'envelops':
cond.append(['cooperative_state', '!=', 'associated'])
# cond.append(['cooperative_state', '!=', 'unsubscribed'])
if search_type == "full" or search_type == 'members' or search_type == "manage_shift_registrations":
fields = CagetteMember.m_default_fields
if not shift_id is None:
......@@ -878,9 +881,9 @@ class CagetteMember(models.Model):
return res
else:
# TODO differentiate short & subscription_data searches
# TODO differentiate envelops & subscription_data searches
fields = CagetteMember.m_short_default_fields
fields = fields + ['total_partner_owned_share','amount_subscription']
fields = fields + ['total_partner_owned_share', 'amount_subscription']
res = api.search_read('res.partner', cond, fields)
return res
......@@ -959,7 +962,12 @@ class CagetteMember(models.Model):
api = OdooAPI()
res = {}
f = { 'makeups_to_do': int(member_data["target_makeups_nb"]) }
# Prevent setting a negative number of makeups_to_do
# https://redmine.coopdev.fr/issues/6090
# This could happen when bdm has two screens open and clicks on minus btn on a coop line
# with exactly 1 makeup_to_do on both screens
makeups_to_do = max(0,int(member_data["target_makeups_nb"]))
f = { 'makeups_to_do': makeups_to_do }
res_item = api.update('res.partner', [self.id], f)
res = {
'mid': self.id,
......@@ -1386,4 +1394,4 @@ class CagetteUser(models.Model):
return answer
from shifts.models import CagetteShift
\ No newline at end of file
from shifts.models import CagetteShift
......@@ -30,7 +30,8 @@ def index(request):
'Je valide mon service "Comité"'),
'CONFIRME_PRESENT_BTN' : getattr(settings, 'CONFIRME_PRESENT_BTN', 'Présent.e'),
'LATE_MODE': getattr(settings, 'ENTRANCE_WITH_LATE_MODE', False),
'ENTRANCE_VALIDATE_PRESENCE_MESSAGE' : getattr(settings, 'ENTRANCE_VALIDATE_PRESENCE_MESSAGE', '')
'ENTRANCE_VALIDATE_PRESENCE_MESSAGE' : getattr(settings, 'ENTRANCE_VALIDATE_PRESENCE_MESSAGE', ''),
'ALLOW_BOTH_AS_ANSWER_TO_WHO_IS_COMING_TO_SHIFT' : getattr(settings, 'ALLOW_BOTH_AS_ANSWER_TO_WHO_IS_COMING_TO_SHIFT', True)
}
for_shoping_msg = getattr(settings, 'ENTRANCE_COME_FOR_SHOPING_MSG', '')
......
......@@ -565,6 +565,17 @@ function init_calendar_page() {
let new_shift_date = datetime_new_shift.toLocaleDateString("fr-fr", date_options);
let new_shift_time = datetime_new_shift.toLocaleTimeString("fr-fr", time_options);
function showInfoAboutSelectedShift(modal_template, new_shift_date, new_shift_time) {
var new_shift_week_day = new_shift_date.replace(/ .*/,'');
if (on_picking_shift_template_msg.startsWith(new_shift_week_day + " " + new_shift_time + " ")) {
modal_template.find(".on_picking_shift_template_msg").text(
on_picking_shift_template_msg.replace(new_shift_week_day + " " + new_shift_time + " ","")
);
} else {
modal_template.find(".on_picking_shift_template_msg").text("");
}
}
if (selected_shift !== null && can_exchange_shifts()) {
/* shift exchange */
// Set old shift
......@@ -580,6 +591,8 @@ function init_calendar_page() {
modal_template.find(".date_new_shift").text(new_shift_date);
modal_template.find(".time_new_shift").text(new_shift_time);
showInfoAboutSelectedShift(modal_template, new_shift_date, new_shift_time);
openModal(
modal_template.html(),
() => {
......@@ -601,6 +614,9 @@ function init_calendar_page() {
modal_template.find(".date_new_shift").text(new_shift_date);
modal_template.find(".time_new_shift").text(new_shift_time);
showInfoAboutSelectedShift(modal_template, new_shift_date, new_shift_time);
openModal(
modal_template.html(),
() => {
......@@ -629,6 +645,8 @@ function init_calendar_page() {
modal_template.find(".date_new_shift").text(new_shift_date);
modal_template.find(".time_new_shift").text(new_shift_time);
showInfoAboutSelectedShift(modal_template, new_shift_date, new_shift_time);
openModal(
modal_template.html(),
() => {
......
......@@ -32,6 +32,7 @@ def index(request, exception=None):
'block_actions_for_attached_people' : getattr(settings, 'BLOCK_ACTIONS_FOR_ATTACHED_PEOPLE', True),
'permanent_message': getattr(settings, 'PERMANENT_MESSAGE_BELOW_CONNECTION_FIELDS', None),
'block_service_exchange_24h_before' : getattr(settings, 'BLOCK_SERVICE_EXCHANGE_24H_BEFORE', True),
'ALLOW_BOTH_AS_ANSWER_TO_WHO_IS_COMING_TO_SHIFT' : getattr(settings, 'ALLOW_BOTH_AS_ANSWER_TO_WHO_IS_COMING_TO_SHIFT', True)
}
template = loader.get_template('members_space/index.html')
......@@ -164,6 +165,7 @@ def index(request, exception=None):
context['helper_unsubscribe_form_link'] = msettings['helper_unsubscribe_form_link']['value'] if 'helper_unsubscribe_form_link' in msettings else ''
context['covid_form_link'] = msettings['covid_form_link']['value'] if 'covid_form_link' in msettings else ''
context['covid_end_form_link'] = msettings['covid_end_form_link']['value'] if 'covid_end_form_link' in msettings else ''
context['on_picking_shift_template_msg'] = msettings['on_picking_shift_template_msg']['value'] if 'on_picking_shift_template_msg' in msettings else ''
if getattr(settings, 'USE_EXEMPTIONS_SHIFT_TEMPLATE', False) is True:
exemptions_shift_id = CagetteServices.get_exemptions_shift_id()
if exemptions_shift_id is None:
......
......@@ -303,4 +303,15 @@ def get_odoo_account_export_report (export_id, final_format):
report = generate_quadratus_compatible_file(res[0])
else:
report = generate_arithmethique_compatible_file(res[0])
return report
\ No newline at end of file
return report
def get_members_capital_at_date(date,only_active):
try:
if only_active == 'on':
only_active = 1
else:
only_active = 0
return OdooAPI().execute("lacagette.exports", 'get_members_capital_at_date', {'date': date, 'only_active': only_active})
except Exception as e:
coop_logger.error("Erreur get_members_capital_at_date : %s", str(e))
return None
\ No newline at end of file
......@@ -21,6 +21,7 @@ from .views import FieldsView
from .views import ExportCompta
from .views import ExportPOS
from .views import ExportOrders
from .views import ExportCapital
urlpatterns = [
......@@ -33,6 +34,7 @@ urlpatterns = [
url(r'^export_compta$', ExportCompta.as_view(), name='export_compta'),
url(r'^export_pos$', ExportPOS.as_view(), name='Export POS'),
url(r'^export_orders$', ExportOrders.as_view(), name='export_orders'),
url(r'^export_capital$', ExportCapital.as_view(), name='export_capital'),
url(r'^monitor/$', monitor.index),
url(r'^monitor/js_errors$', monitor.js_errors),
url(r'^members/', include('members.urls')),
......
......@@ -435,3 +435,45 @@ class ExportOrders(View):
error = "Une erreur est survenue, merci de contacter le service informatique."
coop_logger.error("Erreur export_orders : %s", str(e))
return JsonResponse({'erreur': error, 'details': str(e)})
class ExportCapital(View):
def get(self, request, *args, **kwargs):
u"""Display form"""
template = loader.get_template('outils/export_capital.html')
context = {'title': 'Export Capital détenu'}
return HttpResponse(template.render(context, request))
def post(self, request, *args, **kwargs):
u"""Generate capital export at given date"""
date = request.POST.get('date')
only_active = request.POST.get('only_active')
capital_by_member_list_query = get_members_capital_at_date(date,only_active)
if 'data' in capital_by_member_list_query:
try:
wb = Workbook()
ws1 = wb.active
ws1.title = "Capital détenu par les membres à la date %s" % date
ws1.append(['Membre', 'Capital détenu (en euros)'])
for line in capital_by_member_list_query['data']:
ws1.append([line['membre'], line['capital_detenu']])
wb_name = 'export_capital_' + date + '.xlsx'
response = HttpResponse(content=save_virtual_workbook(wb),
content_type='application/vnd.openxmlformats-officedocument.spreadsheetml.sheet')
response['Content-Disposition'] = 'attachment; filename=' + wb_name
return response
except Exception as e:
error = "Une erreur est survenue, merci de contacter le service informatique."
coop_logger.error("Erreur export_capital : %s", str(e))
return JsonResponse({'erreur': error, 'details': str(e)})
else:
details = ''
if 'error' in capital_by_member_list_query:
details = capital_by_member_list_query['error']
return JsonResponse({'erreur': "La requête n'a pas aboutie", 'details': details})
......@@ -211,7 +211,7 @@ class CagetteReception(models.Model):
to_reset = []
for p_to_print in products_to_print:
coop_logger.info('candidate to print %s', str(p_to_print))
if p_to_print['to_print'] is True and p_to_print['barcode'][:4] not in noprint_list:
if p_to_print['barcode'] and p_to_print['to_print'] is True and p_to_print['barcode'][:4] not in noprint_list:
try:
tools_url = settings.TOOLS_SERVER + '/products/label_print/'
tools_url += str(p_to_print['product_tmpl_id'][0])
......
......@@ -194,7 +194,9 @@
<div class="col-1"></div>
<a id="associated_btn" class=" btn present">Membre</a>
<a id="partner_btn" class=" btn present">Associé</a>
<a id="both_btn" class=" btn present">Les deux</a>
{% if ALLOW_BOTH_AS_ANSWER_TO_WHO_IS_COMING_TO_SHIFT %}
<a id="both_btn" class=" btn present">Les deux</a>
{% endif %}
<div class="col-1 loading2-container">
<span class="loading2"><img width="75" src="/static/img/Pedro_luis_romani_ruiz.gif" alt="Chargement en cours...." /></span>
</div>
......
<div id="faqBDM" class=" mt-3">
<div class="page_title txtcenter"><h1> Problèmes et demandes </h1></div>
<div class="tiles_container">
<div class="tile full_width_tile">
<p>Un problème ? Une demande ? Une question pas résolue par les fonctionnalités de cet espace membre ?</p
<p>Viens au magasin, on s’en occupe ensemble ! Informations pratiques et horaires d’ouverture disponibles sur :</p>
<p><a href="https://graoucoop.fr" target="_blank">https://graoucoop.fr</a></p>
<p>On ne s’interdit pas de mettre en place une adresse mail et/ou un numéro de téléphone dédié à l’avenir, mais pour l’instant, on préfère le contact humain en direct :)</p>
</div>
</div>
</div>
<div class="tile full_width_tile">
<div class="tile_title">
Comprendre mon statut
</div>
<div class="my_info_line_middle">
<p>À Graoucoop, on se base sur les expériences ayant réussi avant nous. En ce qui concerne ton “statut” de membre, il détermine ton droit de faire tes courses, en fonction de la régularité de ta participation bénévole. </p>
<p>Tant que tu participes 3 heures toutes les 4 semaines, tu es “à jour”.</p>
<p>Si tu rates un service sans l’avoir déplacé, tu es en “alerte” et dois faire un “rattrapage” (à choisir via ton espace membre).</p>
<p>Si tu ne fais pas ton rattrapage, au bout de deux mois, tu peux être “suspendu.e”. Si tu ne donnes pas de nouvelles pendant six mois, tu peux même être “désinscrit.e” (ton créneau de bénévolat est libéré pour permettre à une autre personne de s’y inscrire). </p>
<p>Attention, les “suspendu.e.s” et “désinscrit.e.s” ne peuvent pas faire leurs courses. Passe vite au bureau des membres pour programmer un rattrapage et/ou demander un “délai” !</p>
<p>En cas de maladie ou incapacité, tu peux aussi demander à être “exempté.e”. Dans tous les cas, en cas de souci, passe au bureau des membres au magasin, on t’y recevra bien !</p>
<p>Ci-dessous un schéma approximatif des statuts dans un supermarché coopératif.</p>
</div>
<a href="/static/img/diagramme_etat_statut_cooperateurs.png" target="”_blank”">
<img class="status_info_image" src="/static/img/diagramme_etat_statut_cooperateurs.png" alt="diagramme_etat_statut_cooperateurs">
</a>
</div>
......@@ -63,9 +63,11 @@
</div>
<div id="shift_associate" class=" btn--primary assign_shift_button">
</div>
{% if ALLOW_BOTH_AS_ANSWER_TO_WHO_IS_COMING_TO_SHIFT %}
<div id="shift_both" class=" btn--primary assign_shift_button">
Les deux
</div>
{% endif %}
</div>
</div>
......@@ -74,10 +76,12 @@
<div><span class="date_old_shift"></span> à <span class="time_old_shift"></span></div>
<div>par celui du : </div>
<div><span class="date_new_shift"></span> à <span class="time_new_shift"></span></div>
<div><span class="on_picking_shift_template_msg"></span></div>
</div>
<div id="modal_add_shift_template">
<div>Je suis sur le point de m'inscrire au service du : <span class="date_new_shift"></span> à <span class="time_new_shift"></span></div>
<div><span class="on_picking_shift_template_msg"></span></div>
</div>
<div id="calendar_explaination_template">
......@@ -133,6 +137,7 @@
var member_cant_have_delay_form_link = '{{member_cant_have_delay_form_link}}';
var abcd_calendar_link = "{{abcd_calendar_link}}"
var days_to_hide = "{{daysToHide}}"
var on_picking_shift_template_msg = "{{on_picking_shift_template_msg}}"
var partner_data = {
"partner_id":"{{partnerData.id}}",
"name":"{{partnerData.display_name|safe}}",
......
{% extends "base.html" %}
{% load static %}
{% block additionnal_scripts %}
{% endblock %}
{% block content %}
<form enctype="multipart/form-data" action="/export_capital" method="post">
{% csrf_token %}
<p>
<label for="date">Date :</label>
<input type="date" name="date">
</p>
<p>
<label>
<input type="checkbox" name="only_active" />
Uniquement les actifs (ceux qui le sont aujourd'hui)
</label>
</p>
<input type="submit" class='btn--primary' value="Exporter">
</form>
<p>
<em>
Le fichier est généré en requêtant la facturation des parts sociales (dont celle de rachat).<br/>
</em>
</p>
<script src="{% static "js/all_common.js" %}?v=1651853225"></script>
{% endblock %}
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment