Doc, tools for lokavaluto development
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

2878 lines
107 KiB

# coding: utf-8
from __future__ import unicode_literals
import os
import argparse
import logging
import sys
import requests
from slugify import slugify
try:
stringType = basestring
except NameError: # Python 3, basestring causes NameError
stringType = str
logging.basicConfig()
logger = logging.getLogger(__name__)
def check_request_status(r):
if r.status_code == requests.codes.ok:
logger.info('OK')
else:
logger.error(r.text)
r.raise_for_status()
def get_internal_name(name):
name = name.replace('', 'euro')
slug = slugify(name)
return slug.replace('-', '_')
# Ensemble des constantes nécessaires au fonctionnement du script
ENV = os.environ.get('ENV')
LOCAL_CURRENCY_INTERNAL_NAME = os.environ.get('CURRENCY_SLUG')
NETWORK_INTERNAL_NAME = LOCAL_CURRENCY_INTERNAL_NAME
if ENV != 'prod':
NETWORK_INTERNAL_NAME = ENV + LOCAL_CURRENCY_INTERNAL_NAME
LOCAL_CURRENCY_SYMBOL = os.environ.get('CURRENCY_SYMBOL')
SESSION_TIMEOUT = int(os.environ.get('SESSION_TIMEOUT'))
MAX_LENGTH_PWD = os.environ.get('MAX_LENGTH_PWD')
if ENV != 'prod':
MIN_LENGTH_PWD = 4
else:
MIN_LENGTH_PWD = os.environ.get('MIN_LENGTH_PWD')
# Ensemble des constantes nécessaires à l'API.
constants_by_category = {}
# Nécessaire de placer cette fonction après les variables spécifiques à chaque monnaie
def add_constant(category, name, value):
if category not in constants_by_category.keys():
constants_by_category[category] = {}
internal_name = get_internal_name(name)
# Replace custom currency names by a standard "mlc" for simplification purposes in cyclos_constants.yml file attributes
internal_name = internal_name.replace(NETWORK_INTERNAL_NAME,'mlc')
internal_name = internal_name.replace(LOCAL_CURRENCY_INTERNAL_NAME,'mlc')
internal_name = internal_name.replace(LOCAL_CURRENCY_SYMBOL,'MLC')
constants_by_category[category][internal_name] = value
# Arguments à fournir dans la ligne de commande
parser = argparse.ArgumentParser()
parser.add_argument('url', help='URL of Cyclos')
parser.add_argument('authorization',
help='string to use for Basic Authentication')
parser.add_argument('--debug',
help='enable debug messages',
action='store_true')
args = parser.parse_args()
for k, v in vars(args).items():
logger.debug('args.%s = %s', k, v)
url = args.url.rstrip('/')
if args.debug:
logger.setLevel(logging.DEBUG)
else:
logger.setLevel(logging.INFO)
# URLs des web services
global_web_services = url + '/global/web-rpc/'
network_web_services = url + '/' + NETWORK_INTERNAL_NAME + '/web-rpc/'
# En-têtes pour toutes les requêtes (il n'y a qu'un en-tête, pour
# l'authentification).
headers = {'Authorization': 'Basic ' + args.authorization}
# On fait une 1ère requête en lecture seule uniquement pour vérifier
# si les paramètres fournis sont corrects.
logger.info('Vérification des paramètres fournis...')
r = requests.post(global_web_services + 'network/search',
headers=headers, json={})
check_request_status(r)
networks = r.json()['result']['pageItems']
for network in networks:
if network['internalName'] == NETWORK_INTERNAL_NAME:
logger.info(networks)
raise Exception('Cyclos est déjà configuré, utilisez le fichier cyclos_constants.yml.sample '
'ou supprimez la base...')
# On force une mise à jour de la license pour pouvoir créer des
# utilisateurs tout de suite après la fin du paramétrage.
# Sans ça Cyclos dit que la création d'utilisateurs est désactivée car
# le serveur de license ne peut pas être contacté, et il faut attendre
# quelques minutes (il doit donc y avoir une mise à jour automatique de
# la license dans cet intervalle).
logger.info('Mise à jour de la licence...')
r = requests.post(global_web_services + 'license/onlineUpdate',
headers=headers, json=[])
check_request_status(r)
logger.info('Récupération de la licence...')
r = requests.get(global_web_services + 'license/getLicense', headers=headers)
check_request_status(r)
logger.debug('Clé de licence : %s', r.json()['result']['licenseKey'])
# Récupération de la liste des canaux pour avoir leurs identifiants
# sans les coder en dur (du coup je code en dur leur nom interne mais je
# préfère ça).
logger.info('Récupération de la liste des canaux...')
r = requests.get(global_web_services + 'channels/list', headers=headers)
check_request_status(r)
channels = r.json()['result']
for channel in channels:
if channel['internalName'] == 'main':
ID_CANAL_MAIN_WEB = channel['id']
elif channel['internalName'] == 'webServices':
ID_CANAL_WEB_SERVICES = channel['id']
elif channel['internalName'] == 'pos':
ID_CANAL_PAY_AT_POS = channel['id']
elif channel['internalName'] == 'mobile':
ID_CANAL_MOBILE_APP = channel['id']
logger.debug('ID_CANAL_MAIN_WEB = %s', ID_CANAL_MAIN_WEB)
logger.debug('ID_CANAL_WEB_SERVICES = %s', ID_CANAL_WEB_SERVICES)
logger.debug('ID_CANAL_PAY_AT_POS = %s', ID_CANAL_PAY_AT_POS)
logger.debug('ID_CANAL_MOBILE_APP = %s', ID_CANAL_MOBILE_APP)
# Récupération de la liste des types de mots de passe.
logger.info('Récupération de la liste des types de mots de passe...')
r = requests.get(global_web_services + 'passwordType/list', headers=headers)
check_request_status(r)
password_types = r.json()['result']
for password_type in password_types:
if password_type['internalName'] == 'login':
ID_PASSWORD_LOGIN = password_type['id']
elif password_type['internalName'] == 'pin':
ID_PASSWORD_PIN = password_type['id']
logger.debug('ID_PASSWORD_LOGIN = %s', ID_PASSWORD_LOGIN)
logger.debug('ID_PASSWORD_PIN = %s', ID_PASSWORD_PIN)
# On charge le type de mot de passe pour le modifier :
# validation des mots de passe : entre 8 et 25 caractères
r = requests.get(
global_web_services + 'passwordType/load/' + ID_PASSWORD_LOGIN,
headers=headers
)
check_request_status(r)
login_password_config = r.json()['result']
login_password_config['blockTime'] = {
'amount': 0,
'field': 'MINUTES'
}
#contrainte de validation sur la taille des mots de passe
login_password_config['length'] = {
'min': MIN_LENGTH_PWD,
'max': MAX_LENGTH_PWD,
}
login_password_config['expiresAfter'] = {
'amount': 100,
'field': 'YEARS'
}
r = requests.post(
global_web_services + 'passwordType/save/',
headers=headers,
json=login_password_config
)
check_request_status(r)
# Récupération de la liste des méthodes d'identification.
logger.info("Récupération de la liste des méthodes d'identification...")
r = requests.get(global_web_services + 'principalType/list', headers=headers)
check_request_status(r)
principal_types = r.json()['result']
for principal_type in principal_types:
if principal_type['internalName'] == 'username':
ID_PRINCIPAL_TYPE_LOGIN_NAME = principal_type['id']
logger.debug('ID_PRINCIPAL_TYPE_LOGIN_NAME = %s', ID_PRINCIPAL_TYPE_LOGIN_NAME)
########################################################################
# Modification de la configuration par défaut globale :
# - définition de l'URL racine, pour que l'application web fonctionne
# - choix de la virgule comme séparateur pour les décimales
# - dates au format jour/mois/année
# - heures au format 24 heures
# - activation de l'utilisation des numéros de compte
# - activation du canal "Web services" par défaut pour tous les
# utilisateurs
#
# Remarque : on configure l'accès aux web services comme étant activé
# par défaut et pas comme étant imposé mais comme aucun groupe n'a la
# permission "Manage my channels access", cela revient au même.
#
# D'abord on récupère l'id de la config par défaut.
r = requests.get(global_web_services + 'configuration/getDefault',
headers=headers)
check_request_status(r)
global_default_config_id = r.json()['result']['id']
# On charge la configuration par défaut pour pouvoir la modifier.
r = requests.get(
global_web_services + 'configuration/load/' + global_default_config_id,
headers=headers
)
check_request_status(r)
global_default_config = r.json()['result']
global_default_config['rootUrl'] = url
global_default_config['numberFormat'] = 'COMMA_AS_DECIMAL'
global_default_config['dateFormat'] = 'DMY_SLASH'
global_default_config['timeFormat'] = 'H24'
global_default_config['accountNumberConfiguration'] = {
'enabled': True
}
# pas de contrainte de validation sur la taille des logins
global_default_config['usernameLength'] = {
'min': None,
'max': None
}
global_default_config['defaultEmailPrivacy'] = 'VISIBLE_TO_OTHER_USERS'
# Utile notamment car l'applcation SIMM basée sur Cyclos et non Dolibarr :
# peut-être qu'on voudra avoir accès à ces informations..
global_default_config['addressConfiguration'] = {
'enabledAddressFields': ['ADDRESS_LINE_1','CITY']
}
r = requests.post(
global_web_services + 'configuration/save',
headers=headers,
json=global_default_config
)
check_request_status(r)
# Puis on liste les config de canaux pour retrouver l'id de la config
# du canal "Web services".
r = requests.get(
global_web_services + 'channelConfiguration/list/' + global_default_config_id,
headers=headers
)
check_request_status(r)
for channel_config in r.json()['result']:
if channel_config['channel']['internalName'] == 'webServices':
ws_config_id = channel_config['id']
if channel_config['channel']['internalName'] == 'main':
main_config_id = channel_config['id']
# Ensuite on charge la config du canal "Web services", pour pouvoir la
# modifier.
r = requests.get(
global_web_services + 'channelConfiguration/load/' + ws_config_id,
headers=headers
)
check_request_status(r)
ws_config = r.json()['result']
ws_config['userAccess'] = 'ENFORCED_ENABLED'
ws_config['sessionTimeout'] = {
'amount': int(SESSION_TIMEOUT/60) + 1,
'field': 'MINUTES'
}
r = requests.post(
global_web_services + 'channelConfiguration/save',
headers=headers,
json=ws_config
)
check_request_status(r)
# Enfin, on charge la config du canal "main web", pour pouvoir la modifier : accès par défaut avec possibilité de modification.
# Pourquoi ? On souhaite que les pros n'aient pas accès à Cyclos via le canal main web
r = requests.get(
global_web_services + 'channelConfiguration/load/' + main_config_id,
headers=headers
)
check_request_status(r)
main_config = r.json()['result']
main_config['userAccess'] = 'DEFAULT_ENABLED'
main_config['sessionTimeout'] = {
'amount': 5,
'field': 'MINUTES'
}
r = requests.post(
global_web_services + 'channelConfiguration/save',
headers=headers,
json=main_config
)
check_request_status(r)
########################################################################
# Création du réseau NETWORK_INTERNAL_NAME.
#
# C'est le seul réseau, tout le reste du paramétrage va être fait
# dans ce réseau. On ne crée pas d'administrateur spécifique pour ce
# réseau, on fait tout avec l'admnistrateur global.
# Note : On utilise la méthode save() de l'interface CRUDService. Le
# résultat de la requête est l'id de l'objet créé.
#
def create_network(name, internal_name):
logger.info('Création du réseau "%s"...', name)
r = requests.post(global_web_services + 'network/save',
headers=headers,
json={
'name': NETWORK_INTERNAL_NAME,
'internalName': get_internal_name(name),
'enabled': True
})
check_request_status(r)
network_id = r.json()['result']
logger.debug('network_id = %s', network_id)
return network_id
ID_RESEAU = create_network(
name=NETWORK_INTERNAL_NAME,
internal_name=NETWORK_INTERNAL_NAME,
)
########################################################################
# Création des devises "MLC" et "Euro".
#
def create_currency(name, symbol):
logger.info('Création de la devise "%s"...', name)
r = requests.post(network_web_services + 'currency/save',
headers=headers,
json={
'name': name,
'internalName': get_internal_name(name),
'symbol': symbol,
'suffix': ' ' + symbol,
'precision': 2
})
check_request_status(r)
currency_id = r.json()['result']
logger.debug('currency_id = %s', currency_id)
add_constant('currencies', name, currency_id)
return currency_id
ID_DEVISE_LOCAL_CURRENCY = create_currency(
name=LOCAL_CURRENCY_INTERNAL_NAME,
symbol=LOCAL_CURRENCY_SYMBOL,
)
ID_DEVISE_EURO = create_currency(
name='Euro',
symbol='',
)
########################################################################
# Création du token "Carte NFC".
#
def create_token(name, plural_name,token_type, token_mask, maximum_per_user):
logger.info('Création du token "%s"...', name)
r = requests.post(network_web_services + 'principalType/save',
headers=headers,
json={
'class': 'org.cyclos.model.access.principaltypes.TokenPrincipalTypeDTO',
'name': name,
'pluralName': plural_name,
'internalName': get_internal_name(name),
'tokenType': token_type,
'tokenMask': token_mask,
'maximumPerUser': maximum_per_user,
})
check_request_status(r)
token_id = r.json()['result']
logger.debug('token_id = %s', token_id)
add_constant('tokens', name, token_id)
return token_id
ID_TOKEN_CARTE_NFC = create_token(
name='Carte NFC',
plural_name='Cartes NFC',
token_type='NFC_TAG',
token_mask='#### #### #### ####',
maximum_per_user=100,
)
all_token_types = [
ID_TOKEN_CARTE_NFC,
]
########################################################################
# Création des accès clients
# Création du client "Point de vente NFC".
#
def create_access_client(name, plural_name, maximum_per_user, permission):
logger.info('Création du client "%s"...', name)
r = requests.post(network_web_services + 'principalType/save',
headers=headers,
json={
'class': 'org.cyclos.model.access.principaltypes.AccessClientPrincipalTypeDTO',
'name': name,
'pluralName': plural_name,
'internalName': get_internal_name(name),
'maximumPerUser': maximum_per_user,
'permission': permission,
})
check_request_status(r)
access_client_id = r.json()['result']
logger.debug('access_client_id = %s', access_client_id)
add_constant('access_clients', name, access_client_id)
return access_client_id
ID_CLIENT_POINT_DE_VENTE_NFC = create_access_client(
name='Point de vente NFC',
plural_name='Points de vente NFC',
maximum_per_user=10,
permission='RECEIVE_PAYMENT',
)
#@WARNING : utile uniquement pour le Cairn dans le cadre du paiement SMS
ID_CLIENT_SMS = create_access_client(
name='Client SMS',
plural_name='Clients SMS',
maximum_per_user=1,
permission='RECEIVE_AND_MAKE_PAYMENT',
)
#@WARNING : utile uniquement pour le Cairn afin d'authentifier chaque utilisateur via l'app CEL
ID_CLIENT_MAIN = create_access_client(
name='main',
plural_name='mains',
maximum_per_user=1,
permission='ALL',
)
all_access_clients = [
ID_CLIENT_POINT_DE_VENTE_NFC,
ID_CLIENT_SMS,
ID_CLIENT_MAIN
]
#########################################################################
# Modification de la configuration des canaux "Pay at POS", "Mobile
# app" et "web services"
# La configuration par défaut pour chaque canal est héritée de la
# configuration globale. Pour personnaliser cette configuration au
# niveau du réseau MLC, il faut créer une nouvelle configuration
# pour chaque canal.
# Ensuite on personnalise les configurations de la manière suivante :
# - activation de chaque canal par défaut pour tous les utilisateurs
# - canal "Pay at POS" : le mot de passe de confirmation est le code PIN
# - canal "Mobile app" : on définit deux méthodes d'identification pour
# se connecter à l'application mobile :
# - le login, pour les connexions "normales"
# - le client "Point de vente NFC", pour pouvoir se connecter à
# l'application mobile en mode point de vente (POS)
# et on définit le token "Carte NFC" comme méthode d'identification
# pour recevoir des paiements en mode POS.
#
# Remarque : Il faut faire ces modifications après avoir créé le token
# "Carte NFC" et l'access client "Point de vente NFC" car nous en avons
# besoin pour configurer le canal "Mobile app".
# - canal "web services" : on définit deux méthodes d'identification pour
# se connecter :
# - le login, pour les connexions "normales" via le site wen
# - le client "Main", pour pouvoir se connecter à
# cyclos en web services
# - le client "SMS" pour réaliser des paiement lors d'un paiement par SMS
#
# Remarque : Il faut faire ces modifications après avoir créé
# les access client car nous en avons
# besoin pour configurer le canal "web services".
#
def get_data_for_new_channel_configuration(channel, configuration):
logger.debug("get_data_for_new_channel_configuration(%s, %s)", channel, configuration)
r = requests.post(network_web_services + 'channelConfiguration/getDataForNew/',
headers=headers,
json={
'channel': channel,
'configuration': configuration,
})
check_request_status(r)
return r.json()['result']['dto']
# D'abord on récupère l'id de la config par défaut.
logger.info('Récupération de l\'id de la configuration par défaut...')
r = requests.get(network_web_services + 'configuration/getDefault',
headers=headers)
check_request_status(r)
mlc_default_config_id = r.json()['result']['id']
# Puis on crée une nouvelle configuration pour le canal "Pay at POS".
logger.info('Création d\'une nouvelle configuration pour le canal "Pay at POS"...')
new_pos_config = get_data_for_new_channel_configuration(
channel=ID_CANAL_PAY_AT_POS,
configuration=mlc_default_config_id)
new_pos_config['defined'] = True
new_pos_config['enabled'] = True
new_pos_config['userAccess'] = 'DEFAULT_ENABLED'
new_pos_config['confirmationPassword'] = ID_PASSWORD_PIN
logger.info('Sauvegarde de la nouvelle configuration de canal...')
r = requests.post(
network_web_services + 'channelConfiguration/save',
headers=headers,
json=new_pos_config
)
check_request_status(r)
# De le même manière, on crée une nouvelle configuration pour le canal
# "Mobile app".
logger.info('Création d\'une nouvelle configuration pour le canal "Mobile app"...')
new_mobile_app_config = get_data_for_new_channel_configuration(
channel=ID_CANAL_MOBILE_APP,
configuration=mlc_default_config_id)
new_mobile_app_config['defined'] = True
new_mobile_app_config['enabled'] = True
new_mobile_app_config['userAccess'] = 'DEFAULT_ENABLED'
new_mobile_app_config['principalTypes'] = [
ID_PRINCIPAL_TYPE_LOGIN_NAME,
ID_CLIENT_POINT_DE_VENTE_NFC,
]
new_mobile_app_config['receivePaymentPrincipalTypes'] = [
ID_TOKEN_CARTE_NFC,
]
logger.info('Sauvegarde de la nouvelle configuration de canal...')
r = requests.post(
network_web_services + 'channelConfiguration/save',
headers=headers,
json=new_mobile_app_config
)
check_request_status(r)
# De le même manière, on crée une nouvelle configuration pour le canal
# "services web".
logger.info('Création d\'une nouvelle configuration pour le canal "Web services"...')
new_ws_config = get_data_for_new_channel_configuration(
channel=ID_CANAL_WEB_SERVICES,
configuration=mlc_default_config_id)
new_ws_config['defined'] = True
new_ws_config['enabled'] = True
new_ws_config['userAccess'] = 'ENFORCED_ENABLED'
new_ws_config['principalTypes'] = [
ID_PRINCIPAL_TYPE_LOGIN_NAME,
ID_CLIENT_MAIN,
ID_CLIENT_SMS
]
logger.info('Sauvegarde de la nouvelle configuration de canal...')
r = requests.post(
network_web_services + 'channelConfiguration/save',
headers=headers,
json=new_ws_config
)
check_request_status(r)
########################################################################
# Création d'une configuration spécifique pour les groupes "Opérateurs
# BDC" et "Gestion interne".
#
# Par défaut le délai de validité des sessions via les services web est
# de 5 minutes. Ce délai est trop court et rend l'utilisation des
# applications BDC et Gestion Interne pénible.
# On crée donc une nouvelle configuration identique à celle par défaut
# mais dans laquelle les sessions créées vis les services web sont
# valables 2h.
#
def get_data_for_new_configuration(parent_configuration):
logger.debug("get_data_for_new_configuration(%s)", parent_configuration)
r = requests.post(network_web_services + 'configuration/getDataForNew/',
headers=headers,
json=[parent_configuration])
check_request_status(r)
return r.json()['result']['dto']
# D'abord on crée une nouvelle configuration qui hérite de la config par
# défaut.
logger.info("Création d'une nouvelle configuration pour les opérateurs BDC...")
operateur_bdc_config = get_data_for_new_configuration(mlc_default_config_id)
operateur_bdc_config['name'] = 'Opérateurs BDC'
logger.info('Sauvegarde de la nouvelle configuration...')
r = requests.post(
network_web_services + 'configuration/save',
headers=headers,
json=operateur_bdc_config
)
check_request_status(r)
ID_CONFIG_OPERATEURS_BDC = r.json()['result']
# Puis on crée une nouvelle configuration pour le canal "Web services".
logger.info('Création d\'une nouvelle configuration pour le canal "Web services"...')
operateur_bdc_ws_config = get_data_for_new_channel_configuration(
channel=ID_CANAL_WEB_SERVICES,
configuration=ID_CONFIG_OPERATEURS_BDC)
operateur_bdc_ws_config['defined'] = True
operateur_bdc_ws_config['sessionTimeout']['amount'] = 2
operateur_bdc_ws_config['sessionTimeout']['field'] = 'HOURS'
logger.info('Sauvegarde de la nouvelle configuration de canal...')
r = requests.post(
network_web_services + 'channelConfiguration/save',
headers=headers,
json=operateur_bdc_ws_config
)
check_request_status(r)
# On fait la même chose pour Gestion interne.
logger.info("Création d'une nouvelle configuration pour Gestion interne...")
gestion_interne = get_data_for_new_configuration(mlc_default_config_id)
gestion_interne['name'] = 'Gestion interne'
logger.info('Sauvegarde de la nouvelle configuration...')
r = requests.post(
network_web_services + 'configuration/save',
headers=headers,
json=gestion_interne
)
check_request_status(r)
ID_CONFIG_GESTION_INTERNE = r.json()['result']
logger.info('Création d\'une nouvelle configuration pour le canal "Web services"...')
gestion_interne_ws_config = get_data_for_new_channel_configuration(
channel=ID_CANAL_WEB_SERVICES,
configuration=ID_CONFIG_GESTION_INTERNE)
gestion_interne_ws_config['defined'] = True
gestion_interne_ws_config['sessionTimeout']['amount'] = 2
gestion_interne_ws_config['sessionTimeout']['field'] = 'HOURS'
logger.info('Sauvegarde de la nouvelle configuration de canal...')
r = requests.post(
network_web_services + 'channelConfiguration/save',
headers=headers,
json=gestion_interne_ws_config
)
check_request_status(r)
########################################################################
# Création des champs personnalisés pour les paiements.
#
# Note: On a besoin de la liste des champs personnalisés pour créer les
# types de compte puis les types de paiement, c'est pour cette raison
# qu'ils sont créés en premier.
def create_transaction_custom_field_linked_user(name, required=True):
logger.info('Création du champ personnalisé "%s"...', name)
r = requests.post(network_web_services + 'transactionCustomField/save',
headers=headers,
json={
'name': name,
'internalName': get_internal_name(name),
'type': 'LINKED_ENTITY',
'linkedEntityType': 'USER',
'control': 'ENTITY_SELECTION',
'required': required
})
check_request_status(r)
custom_field_id = r.json()['result']
logger.debug('custom_field_id = %s', custom_field_id)
add_constant('transaction_custom_fields', name, custom_field_id)
return custom_field_id
def create_transaction_custom_field_single_selection(name,
possible_values_name,
possible_values,
required=True):
logger.info('Création du champ personnalisé "%s"...', name)
r = requests.post(network_web_services + 'transactionCustomField/save',
headers=headers,
json={
'name': name,
'internalName': get_internal_name(name),
'type': 'SINGLE_SELECTION',
'control': 'SINGLE_SELECTION',
'required': required
})
check_request_status(r)
custom_field_id = r.json()['result']
logger.debug('custom_field_id = %s', custom_field_id)
add_constant('transaction_custom_fields', name, custom_field_id)
for value in possible_values:
logger.info('Ajout de la valeur possible "%s"...', value)
r = requests.post(network_web_services + 'transactionCustomFieldPossibleValue/save',
headers=headers,
json={
'field': custom_field_id,
'value': value
})
check_request_status(r)
possible_value_id = r.json()['result']
add_constant(possible_values_name, value, possible_value_id)
return custom_field_id
def create_transaction_custom_field_text(name, unique=False,
required=True):
logger.info('Création du champ personnalisé "%s"...', name)
r = requests.post(network_web_services + 'transactionCustomField/save',
headers=headers,
json={
'name': name,
'internalName': get_internal_name(name),
'type': 'STRING',
'size': 'LARGE',
'control': 'TEXT',
'unique': unique,
'required': required
})
check_request_status(r)
custom_field_id = r.json()['result']
logger.debug('custom_field_id = %s', custom_field_id)
add_constant('transaction_custom_fields', name, custom_field_id)
return custom_field_id
def create_transaction_custom_field_decimal(name, required=True):
logger.info('Création du champ personnalisé "%s"...', name)
r = requests.post(network_web_services + 'transactionCustomField/save',
headers=headers,
json={
'name': name,
'internalName': get_internal_name(name),
'type': 'DECIMAL',
'decimalDigits': 2,
'control': 'TEXT',
'required': required
})
check_request_status(r)
custom_field_id = r.json()['result']
logger.debug('custom_field_id = %s', custom_field_id)
add_constant('transaction_custom_fields', name, custom_field_id)
return custom_field_id
def add_custom_field_to_transfer_type(transfer_type_id, custom_field_id):
logger.info("Ajout d'un champ personnalisé...")
r = requests.post(network_web_services + 'transactionCustomField/addRelation',
headers=headers,
json=[transfer_type_id, custom_field_id])
check_request_status(r)
ID_CHAMP_PERSO_PAIEMENT_BDC = create_transaction_custom_field_linked_user(
name='BDC',
)
ID_CHAMP_PERSO_PAIEMENT_PORTEUR = create_transaction_custom_field_linked_user(
name='Porteur',
)
ID_CHAMP_PERSO_PAIEMENT_ADHERENT = create_transaction_custom_field_linked_user(
name='Adhérent',
)
ID_CHAMP_PERSO_PAIEMENT_ADHERENT_FACULTATIF = create_transaction_custom_field_linked_user(
name='Adhérent (facultatif)',
required=False,
)
ID_CHAMP_PERSO_PAIEMENT_MODE_DE_PAIEMENT = create_transaction_custom_field_single_selection(
name='Mode de paiement',
possible_values_name='payment_modes',
possible_values=[
'Chèque',
'Espèces',
'Paiement en ligne',
'Prélèvement',
'Virement',
],
)
ID_CHAMP_PERSO_PAIEMENT_PRODUIT = create_transaction_custom_field_single_selection(
name='Produit',
possible_values_name='products',
possible_values=[
'Foulard',
],
)
ID_CHAMP_PERSO_PAIEMENT_NUMERO_BORDEREAU = create_transaction_custom_field_text(
name='Numéro de bordereau',
required=False,
)
ID_CHAMP_PERSO_PAIEMENT_MONTANT_COTISATIONS = create_transaction_custom_field_decimal(
name='Montant Cotisations',
)
ID_CHAMP_PERSO_PAIEMENT_MONTANT_VENTES = create_transaction_custom_field_decimal(
name='Montant Ventes',
)
ID_CHAMP_PERSO_PAIEMENT_MONTANT_CHANGES_BILLET = create_transaction_custom_field_decimal(
name='Montant Changes billet',
)
ID_CHAMP_PERSO_PAIEMENT_MONTANT_CHANGES_NUMERIQUE = create_transaction_custom_field_decimal(
name='Montant Changes numérique',
)
ID_CHAMP_PERSO_PAIEMENT_NUMERO_TRANSACTION_BANQUE = create_transaction_custom_field_text(
name='Numéro de transaction banque',
)
ID_CHAMP_PERSO_PAIEMENT_NUMERO_FACTURE = create_transaction_custom_field_text(
name='Numéro de facture',
unique=True,
)
all_transaction_fields = [
ID_CHAMP_PERSO_PAIEMENT_BDC,
ID_CHAMP_PERSO_PAIEMENT_PORTEUR,
ID_CHAMP_PERSO_PAIEMENT_ADHERENT,
ID_CHAMP_PERSO_PAIEMENT_ADHERENT_FACULTATIF,
ID_CHAMP_PERSO_PAIEMENT_MODE_DE_PAIEMENT,
ID_CHAMP_PERSO_PAIEMENT_PRODUIT,
ID_CHAMP_PERSO_PAIEMENT_NUMERO_BORDEREAU,
ID_CHAMP_PERSO_PAIEMENT_MONTANT_COTISATIONS,
ID_CHAMP_PERSO_PAIEMENT_MONTANT_VENTES,
ID_CHAMP_PERSO_PAIEMENT_MONTANT_CHANGES_BILLET,
ID_CHAMP_PERSO_PAIEMENT_MONTANT_CHANGES_NUMERIQUE,
ID_CHAMP_PERSO_PAIEMENT_NUMERO_TRANSACTION_BANQUE,
ID_CHAMP_PERSO_PAIEMENT_NUMERO_FACTURE,
]
########################################################################
# Création des types de comptes.
#
# Note : La méthode save() de l'interface AccountTypeService prend en
# paramètre un objet de type AccountTypeDTO. AccountTypeDTO a deux
# sous-classes, SystemAccountTypeDTO et UserAccountTypeDTO. Lorsque l'on
# appelle la méthode save(), il faut passer en paramètre un objet du
# type adéquat (selon que l'on crée un compte système ou un compte
# utilisateur) et il faut indiquer explicitement quelle est la classe de
# l'objet passé en paramètre, sinon on se prend l'erreur suivante :
# java.lang.IllegalStateException: Could not instantiate bean of class
# org.cyclos.entities.banking.AccountType.
#
# Note: 'customFieldsForList' définit la liste des champs personnalisés
# visibles dans l'historique du compte. On ne fait pas dans le détail et
# et on donne la liste de tous les champs à chaque fois. Le résultat
# n'est pas terrible dans l'application web mais ce n'est pas grave.
def create_system_account_type(name, currency_id, limit_type):
logger.info('Création du type de compte système "%s"...', name)
params = {
'class': 'org.cyclos.model.banking.accounttypes.SystemAccountTypeDTO',
'name': name,
'internalName': get_internal_name(name),
'currency': currency_id,
'limitType': limit_type,
'customFieldsForList': all_transaction_fields,
}
if limit_type == 'LIMITED':
params['creditLimit'] = 0
r = requests.post(network_web_services + 'accountType/save',
headers=headers, json=params)
check_request_status(r)
account_type_id = r.json()['result']
logger.debug('account_type_id = %s', account_type_id)
add_constant('account_types', name, account_type_id)
return account_type_id
def create_user_account_type(name, currency_id):
logger.info('Création du type de compte utilisateur "%s"...', name)
params = {
'class': 'org.cyclos.model.banking.accounttypes.UserAccountTypeDTO',
'name': name,
'internalName': get_internal_name(name),
'currency': currency_id,
'customFieldsForList': all_transaction_fields,
}
r = requests.post(network_web_services + 'accountType/save',
headers=headers, json=params)
check_request_status(r)
account_type_id = r.json()['result']
logger.debug('account_type_id = %s', account_type_id)
add_constant('account_types', name, account_type_id)
return account_type_id
# Comptes système pour l'mlc billet
ID_COMPTE_DE_DEBIT_CURRENCY_BILLET = create_system_account_type(
name='Compte de débit ' + LOCAL_CURRENCY_INTERNAL_NAME + ' billet',
currency_id=ID_DEVISE_LOCAL_CURRENCY,
limit_type='UNLIMITED',
)
ID_STOCK_DE_BILLETS = create_system_account_type(
name='Stock de billets',
currency_id=ID_DEVISE_LOCAL_CURRENCY,
limit_type='LIMITED',
)
ID_COMPTE_DE_TRANSIT = create_system_account_type(
name='Compte de transit',
currency_id=ID_DEVISE_LOCAL_CURRENCY,
limit_type='LIMITED',
)
ID_COMPTE_DES_BILLETS_EN_CIRCULATION = create_system_account_type(
name='Compte des billets en circulation',
currency_id=ID_DEVISE_LOCAL_CURRENCY,
limit_type='LIMITED',
)
ID_COMPTE_DE_DEBIT_EURO = create_system_account_type(
name='Compte de débit €',
currency_id=ID_DEVISE_EURO,
limit_type='UNLIMITED',
)
# Comptes des bureaux de change :
# - Stock de billets : stock d'mlc disponible pour le change (mlc
# billet) et les retraits (mlc numérique)
# - Caisse € : € encaissés pour les changes, cotisations et ventes
# - Caisse mlc : mlc encaissés pour les cotisations et ventes
# - Retours d'mlc : mlc retournés par les prestataires pour les
# reconvertir en € ou les déposer sur leur compte
ID_STOCK_DE_BILLETS_BDC = create_user_account_type(
name='Stock de billets BDC',
currency_id=ID_DEVISE_LOCAL_CURRENCY,
)
ID_CAISSE_EURO_BDC = create_user_account_type(
name='Caisse € BDC',
currency_id=ID_DEVISE_EURO,
)
ID_CAISSE_CURRENCY_BDC = create_user_account_type(
name='Caisse '+ LOCAL_CURRENCY_INTERNAL_NAME +' BDC',
currency_id=ID_DEVISE_LOCAL_CURRENCY,
)
ID_RETOURS_CURRENCY_BDC = create_user_account_type(
name="Retours d'" + LOCAL_CURRENCY_INTERNAL_NAME + " BDC",
currency_id=ID_DEVISE_LOCAL_CURRENCY,
)
# Comptes utilisateur pour la gestion interne des €
# - pour le Crédit Agricole et La Banque Postale
# - pour les 2 comptes dédiés (mlc billet et mlc numérique)
ID_BANQUE_DE_DEPOT = create_user_account_type(
name='Banque de dépôt',
currency_id=ID_DEVISE_EURO,
)
ID_COMPTE_DEDIE = create_user_account_type(
name='Compte dédié',
currency_id=ID_DEVISE_EURO,
)
# Comptes pour la monnaie locale numérique
ID_COFFRE_MLC_NUMERIQUE = create_system_account_type(
name='Compte de credit coffre numerique',
currency_id=ID_DEVISE_LOCAL_CURRENCY,
limit_type='UNLIMITED',
)
ID_COMPTE_DE_DEBIT_CURRENCY_NUMERIQUE = create_system_account_type(
name='Compte de débit ' + LOCAL_CURRENCY_INTERNAL_NAME + ' numérique',
currency_id=ID_DEVISE_LOCAL_CURRENCY,
limit_type='UNLIMITED',
)
ID_COMPTE_ADHERENT = create_user_account_type(
name="Compte d'adhérent",
currency_id=ID_DEVISE_LOCAL_CURRENCY,
)
all_system_accounts = [
ID_COMPTE_DE_DEBIT_CURRENCY_BILLET,
ID_STOCK_DE_BILLETS,
ID_COMPTE_DE_TRANSIT,
ID_COMPTE_DES_BILLETS_EN_CIRCULATION,
ID_COMPTE_DE_DEBIT_EURO,
ID_COMPTE_DE_DEBIT_CURRENCY_NUMERIQUE,
ID_COFFRE_MLC_NUMERIQUE
]
all_user_accounts = [
ID_STOCK_DE_BILLETS_BDC,
ID_CAISSE_EURO_BDC,
ID_CAISSE_CURRENCY_BDC,
ID_RETOURS_CURRENCY_BDC,
ID_BANQUE_DE_DEPOT,
ID_COMPTE_DEDIE,
ID_COMPTE_ADHERENT,
]
########################################################################
# Création des "status flow" pour les paiements.
#
def create_transfer_status_flow(name):
logger.info('Création du "status flow" "%s"...', name)
r = requests.post(network_web_services + 'transferStatusFlow/save',
headers=headers,
json={
'name': name,
'internalName': get_internal_name(name),
})
check_request_status(r)
status_flow_id = r.json()['result']
logger.debug('status_flow_id = %s', status_flow_id)
add_constant('transfer_status_flows', name, status_flow_id)
return status_flow_id
def create_transfer_status(name, status_flow, possible_next=None):
logger.info('Création du statut "%s"...', name)
status = {
'name': name,
'internalName': get_internal_name(name),
'flow': status_flow,
}
if possible_next:
status['possibleNext'] = possible_next
r = requests.post(network_web_services + 'transferStatus/save',
headers=headers,
json=status)
check_request_status(r)
status_id = r.json()['result']
logger.debug('status_id = %s', status_id)
add_constant('transfer_statuses', name, status_id)
return status_id
# Rapprochement : pour toutes les opérations pour lesquelles on
# souhaite faire des rapprochements.
ID_STATUS_FLOW_RAPPROCHEMENT = create_transfer_status_flow(
name='Rapprochement',
)
ID_STATUS_RAPPROCHE = create_transfer_status(
name='Rapproché',
status_flow=ID_STATUS_FLOW_RAPPROCHEMENT,
)
ID_STATUS_A_RAPPROCHER = create_transfer_status(
name='A rapprocher',
status_flow=ID_STATUS_FLOW_RAPPROCHEMENT,
possible_next=ID_STATUS_RAPPROCHE,
)
# Remise à Euskal Moneta : pour tous les paiements qui créditent les
# caisses €, mlc et retours d'mlc des bureaux de change.
ID_STATUS_FLOW_REMISE_A_ASSO = create_transfer_status_flow(
name="Remise à l'Assocation",
)
ID_STATUS_REMIS = create_transfer_status(
name="Remis à l'Assocation",
status_flow=ID_STATUS_FLOW_REMISE_A_ASSO,
)
ID_STATUS_A_REMETTRE = create_transfer_status(
name="A remettre à l'Assocation",
status_flow=ID_STATUS_FLOW_REMISE_A_ASSO,
possible_next=ID_STATUS_REMIS,
)
# Virements : pour les reconversions d'mlc en € (virement à faire au
# prestataire qui a reconverti) et pour les dépôts en banque (virements
# à faire vers les comptes dédiés).
ID_STATUS_FLOW_VIREMENTS = create_transfer_status_flow(
name='Virements',
)
ID_STATUS_VIREMENTS_FAITS = create_transfer_status(
name='Virements faits',
status_flow=ID_STATUS_FLOW_VIREMENTS,
)
ID_STATUS_VIREMENTS_A_FAIRE = create_transfer_status(
name='Virements à faire',
status_flow=ID_STATUS_FLOW_VIREMENTS,
possible_next=ID_STATUS_VIREMENTS_FAITS,
)
all_status_flows = [
ID_STATUS_FLOW_RAPPROCHEMENT,
ID_STATUS_FLOW_REMISE_A_ASSO,
ID_STATUS_FLOW_VIREMENTS,
]
########################################################################
# Création des types de paiement.
#
# Le paramètre "direction" n'est pas nécessaire pour les types de
# paiement SYSTEM_TO_SYSTEM, SYSTEM_TO_USER et USER_TO_SYSTEM, car dans
# ces cas-là, les types de compte d'origine et de destination permettent
# de déduire la direction. Par contre, ce paramètre est requis pour les
# types de paiement de compte utilisateur à compte utilisateur car il
# peut alors prendre la valeur USER_TO_SELF ou USER_TO_USER et cela doit
# être défini explicitement.
# Du coup, je l'ai rendu toujours obligatoire. C'est discutable mais
# définir systématiquement la direction de manière explicite est
# intéressant car cela sert de documentation.
#
# On définit un "maxChargebackTime" de 2 mois, ce qui veut dire que le
# délai maximum pour rejeter un paiment est de 2 mois.
# Note : les paiements pourront être rejetés par les administrateurs du
# groupe "Gestion interne" (voir le paramétrage des permissions).
#
# Par souci de simplicité, tous les types de paiement sont accessibles
# par les 2 canaux "Main web" et "Web services". Ainsi tous les types
# de paiement seront accessibles par l'interface web de Cyclos pour les
# administrateurs du groupe "Gestion interne" (voir le paramétrage des
# permissions), ce qui garantit une capacité à intervenir si nécessaire.
# D'autre part, ils peuvent tous être utilisés par l'API Eusko (ce n'est
# pas forcément nécessaire mais c'est possible, il n'y aura pas de
# question à se poser.
#
def create_payment_transfer_type(name, direction, from_account_type_id,
to_account_type_id, custom_fields=[],
status_flows=[], initial_statuses=[],
channels=[ID_CANAL_MAIN_WEB, ID_CANAL_WEB_SERVICES],
principal_types=[],
allows_recurring_payments=False,
allows_scheduled_payments=False,
description_availability="OPTIONAL"):
logger.info('Création du type de paiement "%s"...', name)
r = requests.post(network_web_services + 'transferType/save',
headers=headers,
json={
'class': 'org.cyclos.model.banking.transfertypes.PaymentTransferTypeDTO',
'name': name,
'internalName': get_internal_name(name),
'direction': direction,
'from': from_account_type_id,
'to': to_account_type_id,
'enabled': True,
'statusFlows': status_flows,
'initialStatuses': initial_statuses,
'maxChargebackTime': {'amount': '2', 'field': 'MONTHS'},
'channels': channels,
'principalTypes': principal_types,
'allowsRecurringPayments': allows_recurring_payments,
'allowsScheduledPayments': allows_scheduled_payments,
'maxInstallments': 1,
'descriptionAvailability': description_availability
})
check_request_status(r)
payment_transfer_type_id = r.json()['result']
logger.debug('payment_transfer_type_id = %s', payment_transfer_type_id)
add_constant('payment_types', name, payment_transfer_type_id)
for custom_field_id in custom_fields:
add_custom_field_to_transfer_type(
transfer_type_id=payment_transfer_type_id,
custom_field_id=custom_field_id,
)
return payment_transfer_type_id
def create_generated_transfer_type(name, direction, from_account_type_id,
to_account_type_id,
description_availability="OPTIONAL"):
logger.info('Création du type de paiement "%s"...', name)
r = requests.post(network_web_services + 'transferType/save',
headers=headers,
json={
'class': 'org.cyclos.model.banking.transfertypes.GeneratedTransferTypeDTO',
'name': name,
'internalName': get_internal_name(name),
'direction': direction,
'from': from_account_type_id,
'to': to_account_type_id,
'descriptionAvailability': description_availability
})
check_request_status(r)
generated_transfer_type_id = r.json()['result']
logger.debug('generated_transfer_type_id = %s', generated_transfer_type_id)
return generated_transfer_type_id
def create_transfer_fee(name, original_transfer_type, generated_transfer_type,
other_currency, payer, receiver, charge_mode, amount):
logger.info('Création des frais de transfert "%s"...', name)
r = requests.post(network_web_services + 'transferFee/save',
headers=headers,
json={
'name': name,
'internalName': get_internal_name(name),
'enabled': True,
'originalTransferType': original_transfer_type,
'generatedTransferType': generated_transfer_type,
'otherCurrency': other_currency,
'payer': payer,
'receiver': receiver,
'chargeMode': charge_mode,
'amount': amount,
})
check_request_status(r)
transfer_fee_id = r.json()['result']
logger.debug('transfer_fee_id = %s', transfer_fee_id)
# Types de paiement pour l'mlc billet
#
ID_TYPE_PAIEMENT_IMPRESSION_BILLETS = create_payment_transfer_type(
name="Impression de billets " + LOCAL_CURRENCY_INTERNAL_NAME,
direction='SYSTEM_TO_SYSTEM',
from_account_type_id=ID_COMPTE_DE_DEBIT_CURRENCY_BILLET,
to_account_type_id=ID_STOCK_DE_BILLETS,
)
ID_TYPE_PAIEMENT_DESTRUCTION_BILLETS = create_payment_transfer_type(
name="Destruction de billets " + LOCAL_CURRENCY_INTERNAL_NAME,
direction='SYSTEM_TO_SYSTEM',
from_account_type_id=ID_STOCK_DE_BILLETS,
to_account_type_id=ID_COMPTE_DE_DEBIT_CURRENCY_BILLET,
)
ID_TYPE_PAIEMENT_SORTIE_COFFRE = create_payment_transfer_type(
name='Sortie coffre',
direction='SYSTEM_TO_SYSTEM',
from_account_type_id=ID_STOCK_DE_BILLETS,
to_account_type_id=ID_COMPTE_DE_TRANSIT,
custom_fields=[
ID_CHAMP_PERSO_PAIEMENT_PORTEUR,
ID_CHAMP_PERSO_PAIEMENT_BDC,
],
status_flows=[
ID_STATUS_FLOW_RAPPROCHEMENT,
],
initial_statuses=[
ID_STATUS_A_RAPPROCHER,
],
)
ID_TYPE_PAIEMENT_ENTREE_COFFRE_NUMERIQUE = create_payment_transfer_type(
name='Creation MLC numeriques',
direction='SYSTEM_TO_SYSTEM',
from_account_type_id=ID_COFFRE_MLC_NUMERIQUE ,
to_account_type_id=ID_COMPTE_DE_DEBIT_CURRENCY_NUMERIQUE ,
)
ID_TYPE_PAIEMENT_SORTIE_COFFRE_NUMERIQUE = create_payment_transfer_type(
name='Destruction MLC numeriques',
direction='SYSTEM_TO_SYSTEM',
from_account_type_id=ID_COMPTE_DE_DEBIT_CURRENCY_NUMERIQUE ,
to_account_type_id=ID_COFFRE_MLC_NUMERIQUE ,
)
ID_TYPE_PAIEMENT_ENTREE_COFFRE = create_payment_transfer_type(
name='Entrée coffre',
direction='SYSTEM_TO_SYSTEM',
from_account_type_id=ID_COMPTE_DE_TRANSIT,
to_account_type_id=ID_STOCK_DE_BILLETS,
custom_fields=[
ID_CHAMP_PERSO_PAIEMENT_PORTEUR,
ID_CHAMP_PERSO_PAIEMENT_BDC,
ID_CHAMP_PERSO_PAIEMENT_ADHERENT_FACULTATIF,
],
)
ID_TYPE_PAIEMENT_ENTREE_STOCK_BDC = create_payment_transfer_type(
name='Entrée stock BDC',
direction='SYSTEM_TO_USER',
from_account_type_id=ID_COMPTE_DE_TRANSIT,
to_account_type_id=ID_STOCK_DE_BILLETS_BDC,
custom_fields=[
ID_CHAMP_PERSO_PAIEMENT_PORTEUR,
],
)
ID_TYPE_PAIEMENT_SORTIE_STOCK_BDC = create_payment_transfer_type(
name='Sortie stock BDC',
direction='USER_TO_SYSTEM',
from_account_type_id=ID_STOCK_DE_BILLETS_BDC,
to_account_type_id=ID_COMPTE_DE_TRANSIT,
custom_fields=[
ID_CHAMP_PERSO_PAIEMENT_PORTEUR,
],
status_flows=[
ID_STATUS_FLOW_RAPPROCHEMENT,
],
initial_statuses=[
ID_STATUS_A_RAPPROCHER,
],
)
# Les mlc sortis de la Caisse mlc du BDC vont dans le compte des
# billets en circulation (dans la pratique, ces mlc rentrent dans la
# caisse mlc de l'Association mais ce sont bien des mlc en
# circulation). Les sorties caisse sont initialement dans l'état
# "A rapprocher" et seront passées dans l'état "Rapproché" lorsque leur
# entrée dans la Caisse mlc d'E.M. sera validée.
ID_TYPE_PAIEMENT_SORTIE_CAISSE_CURRENCY_BDC = create_payment_transfer_type(
name='Sortie caisse ' + LOCAL_CURRENCY_INTERNAL_NAME + ' BDC',
direction='USER_TO_SYSTEM',
from_account_type_id=ID_CAISSE_CURRENCY_BDC,
to_account_type_id=ID_COMPTE_DES_BILLETS_EN_CIRCULATION,
custom_fields=[
ID_CHAMP_PERSO_PAIEMENT_PORTEUR,
],
status_flows=[
ID_STATUS_FLOW_RAPPROCHEMENT,
],
initial_statuses=[
ID_STATUS_A_RAPPROCHER,
],
)
ID_TYPE_PAIEMENT_SORTIE_RETOURS_CURRENCY_BDC = create_payment_transfer_type(
name='Sortie retours ' + LOCAL_CURRENCY_INTERNAL_NAME + ' BDC',
direction='USER_TO_SYSTEM',
from_account_type_id=ID_RETOURS_CURRENCY_BDC,
to_account_type_id=ID_COMPTE_DE_TRANSIT,
custom_fields=[
ID_CHAMP_PERSO_PAIEMENT_PORTEUR,
ID_CHAMP_PERSO_PAIEMENT_ADHERENT,
],
status_flows=[
ID_STATUS_FLOW_RAPPROCHEMENT,
],
initial_statuses=[
ID_STATUS_A_RAPPROCHER,
],
)
ID_TYPE_PAIEMENT_PERTE_DE_BILLETS = create_payment_transfer_type(
name='Perte de billets',
direction='USER_TO_SYSTEM',
from_account_type_id=ID_STOCK_DE_BILLETS_BDC,
to_account_type_id=ID_COMPTE_DES_BILLETS_EN_CIRCULATION,
)
ID_TYPE_PAIEMENT_GAIN_DE_BILLETS = create_payment_transfer_type(
name='Gain de billets',
direction='SYSTEM_TO_USER',
from_account_type_id=ID_COMPTE_DES_BILLETS_EN_CIRCULATION,
to_account_type_id=ID_STOCK_DE_BILLETS_BDC,
)
# Change billets :
# Cette opération se fait en 2 temps :
# 1) l'adhérent(e) donne des € au BDC
# 2) le BDC donne des € à l'adhérent(e) : les mlc sortent du stock de
# billets du BDC et vont dans le compte système "Compte des billets en
# circulation". En effet, une fois donnés à l'adhérent(e), les mlc
# sont "dans la nature", on ne sait pas exactement ce qu'ils deviennent.
#
# Le paiement enregistré est le versement des € et cela génère
# automatiquement le paiement correspondant au fait de donner les mlc
# à l'adhérent(e). On utilise pour cela le mécanisme des frais de
# transaction. Les frais sont payés par le destinataire, çad le BDC, au
# système (le compte des billets en circulation). Ils correspondent à
# 100% du montant du paiement original.
ID_TYPE_PAIEMENT_CHANGE_BILLETS_VERSEMENT_DES_EUROS = create_payment_transfer_type(
name='Change billets - Versement des €',
direction='SYSTEM_TO_USER',
from_account_type_id=ID_COMPTE_DE_DEBIT_EURO,
to_account_type_id=ID_CAISSE_EURO_BDC,
custom_fields=[
ID_CHAMP_PERSO_PAIEMENT_ADHERENT,
ID_CHAMP_PERSO_PAIEMENT_MODE_DE_PAIEMENT,
],
status_flows=[
ID_STATUS_FLOW_REMISE_A_ASSO,
],
initial_statuses=[
ID_STATUS_A_REMETTRE,
],
)
ID_TYPE_PAIEMENT_CHANGE_BILLETS_VERSEMENT_DES_MLC = create_generated_transfer_type(
name='Change billets - Versement des ' + LOCAL_CURRENCY_INTERNAL_NAME,
direction='USER_TO_SYSTEM',
from_account_type_id=ID_STOCK_DE_BILLETS_BDC,
to_account_type_id=ID_COMPTE_DES_BILLETS_EN_CIRCULATION,
)
create_transfer_fee(
name='Change billets - Versement des ' + LOCAL_CURRENCY_INTERNAL_NAME,
original_transfer_type=ID_TYPE_PAIEMENT_CHANGE_BILLETS_VERSEMENT_DES_EUROS,
generated_transfer_type=ID_TYPE_PAIEMENT_CHANGE_BILLETS_VERSEMENT_DES_MLC,
other_currency=True,
payer='DESTINATION',
receiver='SYSTEM',
charge_mode='PERCENTAGE',
amount=1.00,
)
ID_TYPE_PAIEMENT_RECONVERSION_BILLETS = create_payment_transfer_type(
name='Reconversion billets - Versement des MLCs',
direction='SYSTEM_TO_USER',
from_account_type_id=ID_COMPTE_DES_BILLETS_EN_CIRCULATION,
to_account_type_id=ID_RETOURS_CURRENCY_BDC,
custom_fields=[
ID_CHAMP_PERSO_PAIEMENT_ADHERENT,
ID_CHAMP_PERSO_PAIEMENT_NUMERO_FACTURE,
],
status_flows=[
ID_STATUS_FLOW_REMISE_A_ASSO,
ID_STATUS_FLOW_VIREMENTS,
],
initial_statuses=[
ID_STATUS_A_REMETTRE,
ID_STATUS_VIREMENTS_A_FAIRE,
],
)
ID_TYPE_PAIEMENT_COTISATION_EN_EURO = create_payment_transfer_type(
name='Cotisation en €',
direction='SYSTEM_TO_USER',
from_account_type_id=ID_COMPTE_DE_DEBIT_EURO,
to_account_type_id=ID_CAISSE_EURO_BDC,
custom_fields=[
ID_CHAMP_PERSO_PAIEMENT_ADHERENT,
ID_CHAMP_PERSO_PAIEMENT_MODE_DE_PAIEMENT,
],
status_flows=[
ID_STATUS_FLOW_REMISE_A_ASSO,
],
initial_statuses=[
ID_STATUS_A_REMETTRE,
],
)
ID_TYPE_PAIEMENT_COTISATION_EN_MLC = create_payment_transfer_type(
name='Cotisation en mlc',
direction='SYSTEM_TO_USER',
from_account_type_id=ID_COMPTE_DES_BILLETS_EN_CIRCULATION,
to_account_type_id=ID_CAISSE_CURRENCY_BDC,
custom_fields=[
ID_CHAMP_PERSO_PAIEMENT_ADHERENT,
],
status_flows=[
ID_STATUS_FLOW_REMISE_A_ASSO,
],
initial_statuses=[
ID_STATUS_A_REMETTRE,
],
)
ID_TYPE_PAIEMENT_VENTE_EN_EURO = create_payment_transfer_type(
name='Vente en €',
direction='SYSTEM_TO_USER',
from_account_type_id=ID_COMPTE_DE_DEBIT_EURO,
to_account_type_id=ID_CAISSE_EURO_BDC,
custom_fields=[
ID_CHAMP_PERSO_PAIEMENT_PRODUIT,
ID_CHAMP_PERSO_PAIEMENT_MODE_DE_PAIEMENT,
],
status_flows=[
ID_STATUS_FLOW_REMISE_A_ASSO,
],
initial_statuses=[
ID_STATUS_A_REMETTRE,
],
)
ID_TYPE_PAIEMENT_VENTE_EN_MLC = create_payment_transfer_type(
name='Vente en ' + LOCAL_CURRENCY_INTERNAL_NAME,
direction='SYSTEM_TO_USER',
from_account_type_id=ID_COMPTE_DES_BILLETS_EN_CIRCULATION,
to_account_type_id=ID_CAISSE_CURRENCY_BDC,
custom_fields=[
ID_CHAMP_PERSO_PAIEMENT_PRODUIT,
],
status_flows=[
ID_STATUS_FLOW_REMISE_A_ASSO,
],
initial_statuses=[
ID_STATUS_A_REMETTRE,
],
)
# Dépôt en banque :
# 1 type de paiement pour le dépôt proprement dit + 4 types de paiements
# pour régulariser les dépôts dont le montant ne correspond pas au
# montant calculé.
#
# Le dépôt proprement dit :
ID_TYPE_PAIEMENT_DEPOT_EN_BANQUE = create_payment_transfer_type(
name='Dépôt en banque',
direction='USER_TO_USER',
from_account_type_id=ID_CAISSE_EURO_BDC,
to_account_type_id=ID_BANQUE_DE_DEPOT,
custom_fields=[
ID_CHAMP_PERSO_PAIEMENT_MODE_DE_PAIEMENT,
ID_CHAMP_PERSO_PAIEMENT_NUMERO_BORDEREAU,
ID_CHAMP_PERSO_PAIEMENT_MONTANT_COTISATIONS,
ID_CHAMP_PERSO_PAIEMENT_MONTANT_VENTES,
ID_CHAMP_PERSO_PAIEMENT_MONTANT_CHANGES_BILLET,
ID_CHAMP_PERSO_PAIEMENT_MONTANT_CHANGES_NUMERIQUE,
],
status_flows=[
ID_STATUS_FLOW_RAPPROCHEMENT,
ID_STATUS_FLOW_VIREMENTS,
],
initial_statuses=[
ID_STATUS_A_RAPPROCHER,
ID_STATUS_VIREMENTS_A_FAIRE,
],
)
ID_TYPE_PAIEMENT_REGUL_DEPOT_INSUFFISANT = create_payment_transfer_type(
direction='SYSTEM_TO_USER',
name='Régularisation dépôt insuffisant',
from_account_type_id=ID_COMPTE_DE_DEBIT_EURO,
to_account_type_id=ID_BANQUE_DE_DEPOT,
custom_fields=[
ID_CHAMP_PERSO_PAIEMENT_BDC,
],
status_flows=[
ID_STATUS_FLOW_VIREMENTS,
],
initial_statuses=[
ID_STATUS_VIREMENTS_A_FAIRE,
],
)
ID_TYPE_PAIEMENT_BANQUE_VERS_CAISSE_EURO_BDC = create_payment_transfer_type(
name='Paiement de Banque de dépôt vers Caisse € BDC',
direction='USER_TO_USER',
from_account_type_id=ID_BANQUE_DE_DEPOT,
to_account_type_id=ID_CAISSE_EURO_BDC,
status_flows=[
ID_STATUS_FLOW_RAPPROCHEMENT,
ID_STATUS_FLOW_REMISE_A_ASSO,
],
initial_statuses=[
ID_STATUS_A_RAPPROCHER,
ID_STATUS_A_REMETTRE,
],
)
ID_TYPE_PAIEMENT_CAISSE_EURO_BDC_VERS_BANQUE = create_payment_transfer_type(
name='Paiement de Caisse € BDC vers Banque de dépôt',
direction='USER_TO_USER',
from_account_type_id=ID_CAISSE_EURO_BDC,
to_account_type_id=ID_BANQUE_DE_DEPOT,
status_flows=[
ID_STATUS_FLOW_RAPPROCHEMENT,
],
initial_statuses=[
ID_STATUS_A_RAPPROCHER,
],
)
ID_TYPE_PAIEMENT_REGUL_DEPOT_EXCESSIF = create_payment_transfer_type(
name='Régularisation dépôt excessif',
direction='USER_TO_SYSTEM',
from_account_type_id=ID_BANQUE_DE_DEPOT,
to_account_type_id=ID_COMPTE_DE_DEBIT_EURO,
custom_fields=[
ID_CHAMP_PERSO_PAIEMENT_BDC,
],
status_flows=[
ID_STATUS_FLOW_VIREMENTS,
],
initial_statuses=[
ID_STATUS_VIREMENTS_A_FAIRE,
],
)
# Type de paiement utilisé lorsqu'un BDC remet des espèces à Euskal
# Moneta suite à un refus de la banque de prendre ces espèces.
#
# Les € remis à E.M. vont dans le compte de débit et les opérations sont
# initialemnt dans l'état "A rapprocher", ce qui permettra de les
# valider (c'est le même fonctionnement que pour les sorties de la
# Caisse mlc des BDC).
ID_TYPE_PAIEMENT_REMISE_EUROS_EN_CAISSE = create_payment_transfer_type(
name="Remise d'€ en caisse",
direction='USER_TO_SYSTEM',
from_account_type_id=ID_CAISSE_EURO_BDC,
to_account_type_id=ID_COMPTE_DE_DEBIT_EURO,
status_flows=[
ID_STATUS_FLOW_RAPPROCHEMENT,
],
initial_statuses=[
ID_STATUS_A_RAPPROCHER,
],
)
# Paiement utilisé pour les virements depuis les banques de dépôt pour
# l'argent des cotisations, ventes, .... Dans la pratique, cet argent va
# sur le Compte de gestion d'Euskal Moneta mais ce compte n'existe pas
# dans Cyclos et on considère tout simplement que cet argent sort du
# système.
#
# Note : Le Compte de gestion d'Euskal Moneta n'existe pas dans Cyclos
# car il n'aurait donné qu'une vision partielle du Compte de gestion
# réel (celui qui se trouve au Crédit Coopératif). Plutôt que d'avoir un
# compte incomplet (toutes les opérations n'auraient pas été tracées
# dans Cyclos) et dans un état artificiel (le solde aurait été faux,
# complètement déconnecté de la réalité), il a été décidé de ne pas
# avoir ce compte dans Cyclos. Il est donc à l'extérieur du système et
# c'est le Compte de débit en € qui est utilisé pour les paiements qui
# dans la réalité font intervenir le Compte de gestion.
#
# Note 2 : Dans les noms des types de paiements ci-dessous on utilise
# "Compte débit €" et pas "le Compte de débit €" de façon à avoir un
# internalName ne dépassant pas 50 caractères (le internalName étant
# automatiquement généré à partir du nom).
ID_TYPE_PAIEMENT_BANQUE_VERS_COMPTE_DE_DEBIT = create_payment_transfer_type(
name='Virement de Banque de dépôt vers Compte débit €',
direction='USER_TO_SYSTEM',
from_account_type_id=ID_BANQUE_DE_DEPOT,
to_account_type_id=ID_COMPTE_DE_DEBIT_EURO,
)
# Type de paiement utilisé pour les virements depuis les banques de
# dépôt pour l'argent des changes.
ID_TYPE_PAIEMENT_BANQUE_VERS_COMPTE_DEDIE = create_payment_transfer_type(
name='Virement de Banque de dépôt vers Compte dédié',
direction='USER_TO_USER',
from_account_type_id=ID_BANQUE_DE_DEPOT,
to_account_type_id=ID_COMPTE_DEDIE,
)
# Type de paiement utilisé pour les virements de remboursement des
# reconversions.
ID_TYPE_PAIEMENT_COMPTE_DEDIE_VERS_COMPTE_DE_DEBIT = create_payment_transfer_type(
name='Virement de Compte dédié vers Compte débit €',
direction='USER_TO_SYSTEM',
from_account_type_id=ID_COMPTE_DEDIE,
to_account_type_id=ID_COMPTE_DE_DEBIT_EURO,
)
# Le type de paiement ci-dessous, "Virement entre comptes dédiés",
# permettra de régulariser la situation des 2 comptes dédiés lorsque
# des adhérents feront des dépôts de billets sur leur compte numérique
# ou des retraits de billets à partir de ce même compte.
ID_TYPE_PAIEMENT_VIREMENT_ENTRE_COMPTES_DEDIES = create_payment_transfer_type(
name='Virement entre comptes dédiés',
direction='USER_TO_USER',
from_account_type_id=ID_COMPTE_DEDIE,
to_account_type_id=ID_COMPTE_DEDIE,
)
# Les 2 types de paiement suivants sont utilisés lorsqu'un adhérent fait
# un paiement "en ligne" pour créditer son compte numérique.
# On parle ici de change "en ligne" par opposition à "dans un bureau
# de change". Il peut s'agir d'un paiement par prélèvement automatique,
# par virement ou par carte bleue (dans le cas de la VAD c'est-à-dire la
# vente à distance sur Internet).
# L'API Eusko doit générer ces 2 paiements de façon cohérente. Cela ne
# peut pas être géré dans le paramétrage avec des frais car il s'agit de
# 2 paiements de compte système à compte utilisateur, mais pour des
# utilisateurs différents (le compte dédié mlc numérique, et
# l'adhérent dont il faut créditer le compte).
# Le champ "Numéro de transaction banque" contient la référence du
# paiement bancaire réel en €.
ID_TYPE_PAIEMENT_CHANGE_NUMERIQUE_EN_LIGNE_VERSEMENT_DES_EUROS = create_payment_transfer_type(
name='Change numérique en ligne - Versement des €',
direction='SYSTEM_TO_USER',
from_account_type_id=ID_COMPTE_DE_DEBIT_EURO,
to_account_type_id=ID_COMPTE_DEDIE,
custom_fields=[
ID_CHAMP_PERSO_PAIEMENT_NUMERO_TRANSACTION_BANQUE,
],
)
ID_TYPE_PAIEMENT_CHANGE_NUMERIQUE_EN_LIGNE_VERSEMENT_DES_MLC = create_payment_transfer_type(
name='Change numérique en ligne - Versement des ' + LOCAL_CURRENCY_INTERNAL_NAME,
direction='SYSTEM_TO_USER',
from_account_type_id=ID_COMPTE_DE_DEBIT_CURRENCY_NUMERIQUE,
to_account_type_id=ID_COMPTE_ADHERENT,
custom_fields=[
ID_CHAMP_PERSO_PAIEMENT_NUMERO_TRANSACTION_BANQUE,
],
)
# Ce type de paiement sera utilisé lorsqu'un adhérent fera un paiement
# en € dans un bureau de change pour créditer son compte numérique.
# Pour cette opération, l'API Eusko doit générer 2 paiements :
# - un paiement "Change numérique en BDC - Versement des €"
# - un paiement "Crédit du compte"
# C'est l'API qui doit générer ces 2 paiements de façon cohérente. Cela
# ne peut pas être géré dans le paramétrage avec des frais car il s'agit
# de 2 paiements de compte système à compte utilisateur, mais pour des
# utilisateurs différents (le BDC qui reçoit les €, et l'adhérent dont
# il faut créditer le compte).
ID_TYPE_PAIEMENT_CHANGE_NUMERIQUE_EN_BDC = create_payment_transfer_type(
name='Change numérique en BDC - Versement des €',
direction='SYSTEM_TO_USER',
from_account_type_id=ID_COMPTE_DE_DEBIT_EURO,
to_account_type_id=ID_CAISSE_EURO_BDC,
custom_fields=[
ID_CHAMP_PERSO_PAIEMENT_ADHERENT,
ID_CHAMP_PERSO_PAIEMENT_MODE_DE_PAIEMENT,
],
status_flows=[
ID_STATUS_FLOW_REMISE_A_ASSO,
],
initial_statuses=[
ID_STATUS_A_REMETTRE,
],
)
ID_TYPE_PAIEMENT_RECONVERSION_NUMERIQUE = create_payment_transfer_type(
name='Reconversion numérique',
direction='USER_TO_SYSTEM',
from_account_type_id=ID_COMPTE_ADHERENT,
to_account_type_id=ID_COMPTE_DE_DEBIT_CURRENCY_NUMERIQUE,
status_flows=[
ID_STATUS_FLOW_VIREMENTS,
],
initial_statuses=[
ID_STATUS_VIREMENTS_A_FAIRE,
],
)
# Les 2 types de paiement ci-dessous seront utilisés lorsqu'un adhérent
# déposera des mlc billet dans un bureau de change pour créditer son
# compte numérique.
# Pour cette opération, l'API Eusko doit générer 2 paiements :
# - un paiement "Dépôt de billets"
# - un paiement "Crédit du compte"
# Note : voir le commentaire du type de paiement "Change numérique en
# BDC - Versement des €" pour l'explication sur pourquoi cela est fait
# de cette manière.
ID_TYPE_PAIEMENT_DEPOT_DE_BILLETS = create_payment_transfer_type(
name='Dépôt de billets',
direction='SYSTEM_TO_USER',
from_account_type_id=ID_COMPTE_DES_BILLETS_EN_CIRCULATION,
to_account_type_id=ID_RETOURS_CURRENCY_BDC,
custom_fields=[
ID_CHAMP_PERSO_PAIEMENT_ADHERENT,
],
status_flows=[
ID_STATUS_FLOW_REMISE_A_ASSO,
ID_STATUS_FLOW_VIREMENTS,
],
initial_statuses=[
ID_STATUS_A_REMETTRE,
ID_STATUS_VIREMENTS_A_FAIRE,
],
)
ID_TYPE_PAIEMENT_CREDIT_DU_COMPTE = create_payment_transfer_type(
name='Crédit du compte',
direction='SYSTEM_TO_USER',
from_account_type_id=ID_COMPTE_DE_DEBIT_CURRENCY_NUMERIQUE,
to_account_type_id=ID_COMPTE_ADHERENT,
custom_fields=[
ID_CHAMP_PERSO_PAIEMENT_BDC,
],
)
# Les 2 types de paiement ci-dessous seront utilisés lorsqu'un adhérent
# fera un retrait d'mlc billet (à partir de son compte numérique) dans
# un bureau de change.
# Pour cette opération, l'API Eusko doit générer 2 paiements :
# - un paiement "Retrait de billets"
# - un paiement "Retrait du compte"
# Note : c'est le même fonctionnement que pour le dépôt de billets.
#
# Attention, pour le retrait de billets, le compte d'origine est bien
# le stock de billets du bureau de change, et pas sa caisse mlc, car
# on n'a aucun contrôle sur l'approvisionnement de cette caisse mlc.
# Pour être certain que le BDC a des mlc lorsqu'un adhérent veut faire
# un retrait, il faut prendre ces mlc dans le stock de billets du BDC.
# Au départ, nous voulions que ce stock ne soit utilisé que pour le
# change, mais je ne vois pas comment faire autrement.
ID_TYPE_PAIEMENT_RETRAIT_DE_BILLETS = create_payment_transfer_type(
name='Retrait de billets',
direction='USER_TO_SYSTEM',
from_account_type_id=ID_STOCK_DE_BILLETS_BDC,
to_account_type_id=ID_COMPTE_DES_BILLETS_EN_CIRCULATION,
custom_fields=[
ID_CHAMP_PERSO_PAIEMENT_ADHERENT,
],
status_flows=[
ID_STATUS_FLOW_VIREMENTS,
],
initial_statuses=[
ID_STATUS_VIREMENTS_A_FAIRE,
],
)
ID_TYPE_PAIEMENT_RETRAIT_DU_COMPTE = create_payment_transfer_type(
name='Retrait du compte',
direction='USER_TO_SYSTEM',
from_account_type_id=ID_COMPTE_ADHERENT,
to_account_type_id=ID_COMPTE_DE_DEBIT_CURRENCY_NUMERIQUE,
custom_fields=[
ID_CHAMP_PERSO_PAIEMENT_BDC,
],
)
# Et enfin, les types de paiement les plus importants pour l'mlc
# numérique !
# On crée un type de paiement dédié pour le paiement par carte via le
# terminal de paiement, ce qui permettra de distinguer très facilement
# les paiements par virement via le site web des paiements par carte.
# Cela permettra aussi, éventuellement, de définir des règles
# particulières pour l'un ou l'autre de ces moyens de paiement.
ID_TYPE_PAIEMENT_VIREMENT_INTER_ADHERENT = create_payment_transfer_type(
name='Virement inter-adhérent',
direction='USER_TO_USER',
from_account_type_id=ID_COMPTE_ADHERENT,
to_account_type_id=ID_COMPTE_ADHERENT,
allows_recurring_payments=True,
allows_scheduled_payments=True
)
ID_TYPE_PAIEMENT_PAIEMENT_PAR_SMS = create_payment_transfer_type(
name='Paiement par SMS',
direction='USER_TO_USER',
from_account_type_id=ID_COMPTE_ADHERENT,
to_account_type_id=ID_COMPTE_ADHERENT,
principal_types=[
ID_CLIENT_SMS,
],
)
ID_TYPE_PAIEMENT_PAIEMENT_PAR_CARTE = create_payment_transfer_type(
name='Paiement par carte',
direction='USER_TO_USER',
from_account_type_id=ID_COMPTE_ADHERENT,
to_account_type_id=ID_COMPTE_ADHERENT,
channels=[
ID_CANAL_PAY_AT_POS,
],
principal_types=[
ID_TOKEN_CARTE_NFC,
],
)
# Types de paiement pour des régularisations entre caisses des BDC.
ID_TYPE_PAIEMENT_DE_STOCK_DE_BILLETS_BDC_VERS_RETOURS_MLC_BDC = create_payment_transfer_type(
name="De Stock de billets BDC vers Retours de " + LOCAL_CURRENCY_INTERNAL_NAME +" BDC",
direction='USER_TO_SELF',
from_account_type_id=ID_STOCK_DE_BILLETS_BDC,
to_account_type_id=ID_RETOURS_CURRENCY_BDC,
)
ID_TYPE_PAIEMENT_DE_RETOURS_MLC_BDC_VERS_STOCK_DE_BILLETS_BDC = create_payment_transfer_type(
name="De Retours des " + LOCAL_CURRENCY_INTERNAL_NAME + " BDC vers Stock de billets BDC",
direction='USER_TO_SELF',
from_account_type_id=ID_RETOURS_CURRENCY_BDC,
to_account_type_id=ID_STOCK_DE_BILLETS_BDC,
)
all_system_to_system_payments = [
ID_TYPE_PAIEMENT_IMPRESSION_BILLETS,
ID_TYPE_PAIEMENT_DESTRUCTION_BILLETS,
ID_TYPE_PAIEMENT_SORTIE_COFFRE,
ID_TYPE_PAIEMENT_ENTREE_COFFRE,
ID_TYPE_PAIEMENT_ENTREE_COFFRE_NUMERIQUE,
ID_TYPE_PAIEMENT_SORTIE_COFFRE_NUMERIQUE
]
all_system_to_user_payments = [
ID_TYPE_PAIEMENT_ENTREE_STOCK_BDC,
ID_TYPE_PAIEMENT_GAIN_DE_BILLETS,
ID_TYPE_PAIEMENT_CHANGE_BILLETS_VERSEMENT_DES_EUROS,
ID_TYPE_PAIEMENT_RECONVERSION_BILLETS,
ID_TYPE_PAIEMENT_COTISATION_EN_EURO,
ID_TYPE_PAIEMENT_COTISATION_EN_MLC,
ID_TYPE_PAIEMENT_VENTE_EN_EURO,
ID_TYPE_PAIEMENT_VENTE_EN_MLC,
ID_TYPE_PAIEMENT_REGUL_DEPOT_INSUFFISANT,
ID_TYPE_PAIEMENT_CHANGE_NUMERIQUE_EN_LIGNE_VERSEMENT_DES_EUROS,
ID_TYPE_PAIEMENT_CHANGE_NUMERIQUE_EN_LIGNE_VERSEMENT_DES_MLC,
ID_TYPE_PAIEMENT_CHANGE_NUMERIQUE_EN_BDC,
ID_TYPE_PAIEMENT_DEPOT_DE_BILLETS,
ID_TYPE_PAIEMENT_CREDIT_DU_COMPTE,
]
all_user_to_system_payments = [
ID_TYPE_PAIEMENT_SORTIE_STOCK_BDC,
ID_TYPE_PAIEMENT_SORTIE_CAISSE_CURRENCY_BDC,
ID_TYPE_PAIEMENT_SORTIE_RETOURS_CURRENCY_BDC,
ID_TYPE_PAIEMENT_PERTE_DE_BILLETS,
ID_TYPE_PAIEMENT_REGUL_DEPOT_EXCESSIF,
ID_TYPE_PAIEMENT_REMISE_EUROS_EN_CAISSE,
ID_TYPE_PAIEMENT_BANQUE_VERS_COMPTE_DE_DEBIT,
ID_TYPE_PAIEMENT_COMPTE_DEDIE_VERS_COMPTE_DE_DEBIT,
ID_TYPE_PAIEMENT_RECONVERSION_NUMERIQUE,
ID_TYPE_PAIEMENT_RETRAIT_DE_BILLETS,
ID_TYPE_PAIEMENT_RETRAIT_DU_COMPTE,
]
all_user_to_user_payments = [
ID_TYPE_PAIEMENT_DEPOT_EN_BANQUE,
ID_TYPE_PAIEMENT_BANQUE_VERS_CAISSE_EURO_BDC,
ID_TYPE_PAIEMENT_CAISSE_EURO_BDC_VERS_BANQUE,
ID_TYPE_PAIEMENT_BANQUE_VERS_COMPTE_DEDIE,
ID_TYPE_PAIEMENT_VIREMENT_ENTRE_COMPTES_DEDIES,
ID_TYPE_PAIEMENT_VIREMENT_INTER_ADHERENT,
ID_TYPE_PAIEMENT_PAIEMENT_PAR_CARTE,
]
all_user_to_self_payments = [
ID_TYPE_PAIEMENT_DE_STOCK_DE_BILLETS_BDC_VERS_RETOURS_MLC_BDC,
ID_TYPE_PAIEMENT_DE_RETOURS_MLC_BDC_VERS_STOCK_DE_BILLETS_BDC,
]
all_payments_to_system = \
all_system_to_system_payments \
+ all_user_to_system_payments
all_payments_to_user = \
all_system_to_user_payments \
+ all_user_to_user_payments \
+ all_user_to_self_payments
########################################################################
# Creation des scripts et des points d extensions associés aux
# transactions et transferts
def create_custom_script(name,
type,
pathToScript,
dependencies=[],
parameters=None):
logger.info('Création du script "%s"...', name)
# On commence par créer le script avec les propriétés de base.
script = {
'class': 'org.cyclos.model.system.scripts.CustomScriptDTO',
'name': name,
'internalName': get_internal_name(name),
'runAsSystem': True
}
script['type'] = type
script['parameters'] = parameters
with open(pathToScript, 'r') as file:
data = file.read()
script['functions'] = {
'SAVED': data
}
r = requests.post(network_web_services + 'customScript/save',
headers=headers,
json=script)
check_request_status(r)
script_id = r.json()['result']
logger.debug('script_id = %s', script_id)
return script_id
def create_extension_point_with_transfertype(name,
extension_point_class,
transfer_types,
enabled,
script,
events=[]):
logger.info('Création du point d extension "%s"...', name)
# On commence par créer le point d'extension avec les propriétés de base.
extensionPoint = {
'class': extension_point_class,
'name': name,
'internalName': get_internal_name(name),
'enabled': enabled
}
extensionPoint['transferTypes']=transfer_types
extensionPoint['script']=script
extensionPoint['events']=events
r = requests.post(network_web_services + 'extensionPoint/save',
headers=headers,
json=extensionPoint)
check_request_status(r)
extension_point_id = r.json()['result']
logger.debug('extension_point_id = %s', extension_point_id)
return extension_point_id
ID_TRANSACTION_SCRIPT = create_custom_script(
name='Warning failed asynchronous transactions',
type='EXTENSION_POINT',
pathToScript='script_transaction_extensionpoint.groovy'
)
ID_TRANSFER_SCRIPT = create_custom_script(
name='Asynchronous transfer sync',
type='EXTENSION_POINT',
pathToScript='script_transfer_extensionpoint.groovy'
)
ID_TRANSACTION_EXTENSION_POINT = create_extension_point_with_transfertype(
name='Warning failed asynchronous transactions',
extension_point_class='org.cyclos.model.system.extensionpoints.TransactionExtensionPointDTO',
transfer_types= [ID_TYPE_PAIEMENT_VIREMENT_INTER_ADHERENT],
enabled=True,
script=ID_TRANSACTION_SCRIPT,
events=['CHANGE_STATUS']
)
ID_TRANSFER_EXTENSION_POINT = create_extension_point_with_transfertype(
name='Asynchronous transfer sync',
extension_point_class='org.cyclos.model.system.extensionpoints.TransferExtensionPointDTO',
transfer_types=[ID_TYPE_PAIEMENT_VIREMENT_INTER_ADHERENT],
enabled=True,
script=ID_TRANSFER_SCRIPT,
events=['CREATE']
)
########################################################################
# Création des champs personnalisés pour les profils utilisateur.
#
def create_user_custom_field_linked_user(name, required=True):
logger.info('Création du champ personnalisé "%s"...', name)
r = requests.post(network_web_services + 'userCustomField/save',
headers=headers,
json={
'name': name,
'internalName': get_internal_name(name),
'type': 'LINKED_ENTITY',
'linkedEntityType': 'USER',
'control': 'ENTITY_SELECTION',
'required': required
})
check_request_status(r)
custom_field_id = r.json()['result']
logger.debug('custom_field_id = %s', custom_field_id)
add_constant('user_custom_fields', name, custom_field_id)
return custom_field_id
ID_CHAMP_PERSO_UTILISATEUR_BDC = create_user_custom_field_linked_user(
name='BDC',
)
########################################################################
# Création des produits et des groupes.
#
# Les produits servent à gérer les permissions et les règles d'accès, et
# à attribuer des types de compte aux utilisateurs.
#
# Un groupe de nature Administrateur est associé à un unique produit, de
# nature Administrateur, et qui est créé automatiquement lors de la
# création du groupe. C'est dans ce produit que sont définies les
# permissions et les règles d'accès du groupe.
#
# Au contraire, un groupe de nature Membre peut être associé à plusieurs
# produits (de nature Membre) mais aucun n'est créé automatiquement. Là
# encore, c'est via les produits que les permissions et les règles
# d'accès sont définies. Si plusieurs produits sont associés à un
# groupe, les permissions se cumulent.
# Un produit de nature Membre ne peut être lié qu'à un seul type de
# compte utilisateur. Chaque utilisateur appartenant à un groupe associé
# à ce produit aura un compte de ce type.
# Si on veut attribuer plusieurs comptes à des utilisateurs (c'est notre
# cas pour les bureaux de change), il faut créer un produit pour chaque
# type de compte utilisateur et associer tous ces produits au groupe des
# utilisateurs.
#
# Note: Tous les utilisateurs ont un nom et un login, même ceux qui ne
# peuvent pas se connecter à Cyclos (par exemple les utilisateurs des
# groupes "Bureaux de change", "Banques de dépôt" ou "Porteurs"). Comme
# Cyclos vérifie l'unicité du login, cela rend impossible la création de
# doublons (c'est donc une mesure de protection).
def create_member_product(name,
my_profile_fields=[],
accessible_user_groups=[],
other_users_profile_fields={},
user_account_type_id=None,
dashboard_actions=[],
password_actions=[],
my_access_clients=[],
my_token_types=[],
system_payments=[],
user_payments=[],
scheduled_payments=[],
recurring_payments=[],
receive_payments=[]):
logger.info('Création du produit "%s"...', name)
# On commence par créer le produit avec les propriétés de base.
product = {
'class': 'org.cyclos.model.users.products.MemberProductDTO',
'name': name,
'internalName': get_internal_name(name),
# Workaround of a bug in Cyclos 4.6.
'myRecordTypeFields': [],
}
if user_account_type_id:
product['userAccount'] = user_account_type_id
product['accountAccessibility'] = 'ALWAYS'
r = requests.post(network_web_services + 'product/save',
headers=headers,
json=product)
check_request_status(r)
product_id = r.json()['result']
logger.debug('product_id = %s', product_id)
# Ensuite on charge le produit pour pouvoir le modifier.
r = requests.get(
network_web_services + 'product/load/' + product_id,
headers=headers
)
check_request_status(r)
product = r.json()['result']
# On modifie les paramètres du produit puis on l'enregistre.
for field in product['myProfileFields']:
if field['profileField'] in my_profile_fields:
field['enabled'] = True
field['editableAtRegistration'] = True
field['visible'] = True
field['editable'] = True
# Par défaut un utilisateur peut accéder à son propre groupe. C'est
# nécessaire pour qu'un utilisateur soit capable de voir dans quel
# groupe lui-même se trouve (voir aussi 'groupVisibility' plus bas).
if not accessible_user_groups:
product['userGroupAccessibility'] = 'OWN_GROUP'
else:
product['userGroupAccessibility'] = 'SPECIFIC'
product['accessibleUserGroups'] = accessible_user_groups
product['searchUsersOnGroups'] = 'ALL'
# Permettre de voir le group dans lequel un utilisateur se trouve
# (s'applique aussi à soi-même).
product['groupVisibility'] = 'GROUP'
for field in product['userProfileFields']:
key = field['profileField']
try:
if key in other_users_profile_fields:
field['userList'] = True
field['userFilter'] = True
field['visible'] = True
field['userKeywords'] = other_users_profile_fields[key]
except TypeError:
# Pour les champs de profil personnalisés (comme 'BDC'),
# 'profileField' n'est une string mais un dictionnaire et
# un TypeError est balancé. On ignore l'erreur car on ne
# traite ici que les champs de profil standards.
pass
for dashboard_action in product['dashboardActions']:
if dashboard_action['dashboardAction'] in dashboard_actions:
dashboard_action['enabled'] = True
dashboard_action['enabledByDefault'] = True
for password_action in product['passwordActions']:
if password_action['passwordType']['internalName'] in password_actions:
password_action['change'] = True
password_action['atRegistration'] = True
for access_client in product['myAccessClients']:
if access_client['accessClientType']['id'] in my_access_clients:
access_client['enable'] = True
access_client['view'] = True
access_client['block'] = True
access_client['unblock'] = True
access_client['manage'] = True
access_client['activate'] = True
access_client['unassign'] = True
for token_type in product['myTokenTypes']:
if token_type['tokenType']['id'] in my_token_types:
token_type['enable'] = True
token_type['block'] = True
token_type['unblock'] = True
product['maxAddresses'] = 1
product['systemPayments'] = system_payments
product['userPayments'] = user_payments
product['receivePayments'] = receive_payments
product['myScheduledPayments'] = scheduled_payments
product['myRecurringPayments'] = recurring_payments
r = requests.post(network_web_services + 'product/save',
headers=headers,
json=product)
check_request_status(r)
return product_id
def assign_product_to_group(product_id, group_id):
logger.info("Affectation du produit à un groupe...")
r = requests.post(network_web_services + 'productsGroup/assign',
headers=headers,
json=[product_id, group_id])
check_request_status(r)
def get_admin_product(group_id):
r = requests.get(network_web_services + 'group/load/' + group_id,
headers=headers,
json={})
check_request_status(r)
product_id = r.json()['result']['adminProduct']['id']
return product_id
def set_admin_group_permissions(
group_id,
my_profile_fields=[],
password_actions=[],
my_access_clients=[],
visible_transaction_fields=[],
transfer_status_flows=[],
system_accounts=[],
system_to_system_payments=[],
system_to_user_payments=[],
chargeback_of_payments_to_system=[],
accessible_user_groups=[],
accessible_administrator_groups=[],
user_profile_fields=[],
change_group='NONE',
user_registration=False,
blocked_users_manage=False,
disabled_users='NONE',
removed_users='NONE',
user_password_actions=[],
user_channels_access='NONE',
user_token_types=[],
user_access_clients=[],
access_user_accounts=[],
payments_as_user_to_user=[],
payments_as_user_to_system=[],
payments_as_user_to_self=[],
user_scheduled_payments=[],
user_recurring_payments=[],
chargeback_of_payments_to_user=[]
):
# Récupération de l'id du produit de ce groupe.
product_id = get_admin_product(group_id)
# Chargement du produit
r = requests.get(network_web_services + 'product/load/' + product_id,
headers=headers,
json={})
check_request_status(r)
product = r.json()['result']
# Plusieurs champs de profil sont activés par défaut et on doit les
# désactiver si on n'en veut pas.
for profile_field in product['myProfileFields']:
field = profile_field['profileField']
if isinstance(field, stringType):
enable = field in my_profile_fields
elif isinstance(field, dict):
enable = field['id'] in my_profile_fields
profile_field['enabled'] = enable
profile_field['editableAtRegistration'] = enable
profile_field['visible'] = enable
profile_field['editable'] = enable
# Par défaut tous les types de mot de passe sont présents et aucune
# action n'est activée. Pour les types voulus, on active les actions
# 'Change' (modifier le mot de passe) et 'At registration' (définir
# le mot de passe lors de l'enregistrement de l'utilisateur).
for password_action in product['passwordActions']:
if password_action['passwordType']['internalName'] in password_actions:
password_action['change'] = True
password_action['atRegistration'] = True
#access main client
for access_client in product['myAccessClients']:
if access_client['accessClientType']['id'] in my_access_clients:
access_client['enable'] = True
access_client['view'] = True
access_client['block'] = True
access_client['unblock'] = True
access_client['manage'] = True
access_client['activate'] = True
access_client['unassign'] = True
product['visibleTransactionFields'] = visible_transaction_fields
# Status flows.
for product_transfer_status_flow in product['transferStatusFlows']:
if product_transfer_status_flow['flow']['id'] in transfer_status_flows:
product_transfer_status_flow['visible'] = True
product_transfer_status_flow['editable'] = True
product['systemAccounts'] = system_accounts
product['systemToSystemPayments'] = system_to_system_payments
product['systemToUserPayments'] = system_to_user_payments
product['chargebackPaymentsToSystem'] = chargeback_of_payments_to_system
if accessible_user_groups:
product['userGroupAccessibility'] = 'SPECIFIC'
product['accessibleUserGroups'] = accessible_user_groups
if accessible_administrator_groups:
product['adminGroupAccessibility'] = 'SPECIFIC'
product['accessibleAdminGroups'] = accessible_administrator_groups
for profile_field in product['userProfileFields']:
field = profile_field['profileField']
if isinstance(field, stringType):
enable = field in user_profile_fields
elif isinstance(field, dict):
enable = field['id'] in user_profile_fields
profile_field['visible'] = enable
profile_field['editable'] = enable
profile_field['userList'] = enable
profile_field['userKeywords'] = enable
product['userGroup'] = change_group
product['userRegistration'] = user_registration
product['blockedUsersManage'] = blocked_users_manage
product['disabledUsers'] = disabled_users
product['removedUsers'] = removed_users
# Actions possibles sur les mots de passe des autres utilisateurs :
# le principe est le même que pour les 'passwordActions' sauf que
# l'on n'active que l'action 'Change'.
for password_action in product['userPasswordActions']:
if password_action['passwordType']['internalName'] in user_password_actions:
password_action['change'] = True
password_action['atRegistration'] = True
# password_action['reset'] = True
# password_action['unblock'] = True
product['userChannelsAccess'] = user_channels_access
for token_type in product['userTokenTypes']:
if token_type['tokenType']['id'] in user_token_types:
token_type['view'] = True
token_type['block'] = True
token_type['unblock'] = True
token_type['cancel'] = True
token_type['initialize'] = True
token_type['personalize'] = True
token_type['changeDates'] = True
for access_client in product['userAccessClients']:
if access_client['accessClientType']['id'] in user_access_clients:
access_client['view'] = True
access_client['manage'] = True
access_client['block'] = True
access_client['unblock'] = True
access_client['activate'] = True
access_client['unassign'] = True
product['userAccountsAccess'] = access_user_accounts
product['userPaymentsAsUser'] = payments_as_user_to_user
product['systemPaymentsAsUser'] = payments_as_user_to_system
product['selfPaymentsAsUser'] = payments_as_user_to_self
product['chargebackPaymentsToUser'] = chargeback_of_payments_to_user
product['userScheduledPayments'] = user_scheduled_payments #['VIEW','CANCEL','PROCESS_INSTALLMENT']
product['userRecurringPayments'] = user_recurring_payments #['VIEW']
# Enregistrement du produit modifié
r = requests.post(network_web_services + 'product/save',
headers=headers,
json=product)
check_request_status(r)
# TODO factoriser le code de ces 2 fonctions si elles restent telles quelles
# create_group(nature = 'ADMIN' ou 'MEMBER', name)
def create_admin_group(name):
logger.info('Création du groupe Administrateur "%s"...', name)
r = requests.post(network_web_services + 'group/save',
headers=headers,
json={
'class': 'org.cyclos.model.users.groups.AdminGroupDTO',
'name': name,
'internalName': get_internal_name(name),
'initialUserStatus': 'ACTIVE',
'enabled': True
})
check_request_status(r)
group_id = r.json()['result']
logger.debug('group_id = %s', group_id)
add_constant('groups', name, group_id)
return group_id
def create_member_group(name,
initial_user_status='ACTIVE',
products=[]):
logger.info('Création du groupe Membre "%s"...', name)
r = requests.post(network_web_services + 'group/save',
headers=headers,
json={
'class': 'org.cyclos.model.users.groups.MemberGroupDTO',
'name': name,
'internalName': get_internal_name(name),
'initialUserStatus': initial_user_status,
'enabled': True
})
check_request_status(r)
group_id = r.json()['result']
logger.debug('group_id = %s', group_id)
add_constant('groups', name, group_id)
for product_id in products:
assign_product_to_group(product_id, group_id)
return group_id
def change_group_configuration(group_id, configuration_id):
logger.info("Affectation d'une nouvelle configuration à un groupe...")
r = requests.post(network_web_services + 'group/changeConfiguration',
headers=headers,
json=[group_id, configuration_id])
check_request_status(r)
# Gestion interne :
# Les membres de ce groupe ont accès à l'application de gestion interne.
# Ils ont aussi accès à Cyclos, où ils ont toutes les permissions, ce
# qui leur permet d'intervenir au-delà de ce que permet l'application de
# gestion interne (par exemple pour annuler un paiement).
ID_GROUPE_GESTION_INTERNE = create_admin_group(
name='Gestion interne',
)
change_group_configuration(ID_GROUPE_GESTION_INTERNE,
ID_CONFIG_GESTION_INTERNE)
# Opérateurs BDC :
# Les membres de ce groupe ont accès à l'application des bureaux de
# change. Ils ont aussi accès à Cyclos, où ils n'ont que les permissions
# correspondant aux opérations qu'ils peuvent faire dans l'application
# BDC (ils ne peuvent rien faire de plus).
# Un utilisateur est créé dans ce groupe pour chaque bureau de change,
# et lié à l'utilisateur "Bureau de change" correspondant.
ID_GROUPE_OPERATEURS_BDC = create_admin_group(
name='Opérateurs BDC',
)
change_group_configuration(ID_GROUPE_OPERATEURS_BDC,
ID_CONFIG_OPERATEURS_BDC)
# Anonyme :
# Ce groupe ne va contenir qu'un utilisateur : l'utilisateur "anonyme"
# que l'API va utiliser à chaque fois qu'elle devra faire des requêtes
# sans qu'un "vrai" utilisateur ne soit authentifié (par exemple, lors
# de la 1ère connexion d'un adhérent à l'application Compte en ligne).
ID_GROUPE_ANONYME = create_admin_group(
name='Anonyme',
)
# Bureaux de change :
# Un utilisateur est créé dans ce groupe pour chaque bureau de change
# (c'est cet utilisateur qui possèdes les comptes du BDC, par contre
# toutes les opérations sont faites par l'opérateur BDC associé).
ID_PRODUIT_STOCK_DE_BILLETS_BDC = create_member_product(
name='Stock de billets BDC',
my_profile_fields=[
'FULL_NAME',
'LOGIN_NAME',
],
user_account_type_id=ID_STOCK_DE_BILLETS_BDC,
)
ID_PRODUIT_CAISSE_EURO_BDC = create_member_product(
name='Caisse € BDC',
user_account_type_id=ID_CAISSE_EURO_BDC,
)
ID_PRODUIT_CAISSE_MLC_BDC = create_member_product(
name='Caisse '+ LOCAL_CURRENCY_INTERNAL_NAME + ' BDC',
user_account_type_id=ID_CAISSE_CURRENCY_BDC,
)
ID_PRODUIT_RETOURS_MLC_BDC = create_member_product(
name="Retours des " + LOCAL_CURRENCY_INTERNAL_NAME + " BDC",
user_account_type_id=ID_RETOURS_CURRENCY_BDC,
)
ID_GROUPE_BUREAUX_DE_CHANGE = create_member_group(
name='Bureaux de change',
products=[
ID_PRODUIT_STOCK_DE_BILLETS_BDC,
ID_PRODUIT_CAISSE_EURO_BDC,
ID_PRODUIT_CAISSE_MLC_BDC,
ID_PRODUIT_RETOURS_MLC_BDC,
]
)
# Banques de dépôt.
ID_PRODUIT_BANQUE_DE_DEPOT = create_member_product(
name='Banque de dépôt',
my_profile_fields=[
'FULL_NAME',
'LOGIN_NAME',
],
user_account_type_id=ID_BANQUE_DE_DEPOT,
)
ID_GROUPE_BANQUES_DE_DEPOT = create_member_group(
name='Banques de dépôt',
products=[
ID_PRODUIT_BANQUE_DE_DEPOT,
]
)
# Comptes dédiés.
ID_PRODUIT_COMPTE_DEDIE = create_member_product(
name='Compte dédié',
my_profile_fields=[
'FULL_NAME',
'LOGIN_NAME',
],
user_account_type_id=ID_COMPTE_DEDIE,
)
ID_GROUPE_COMPTES_DEDIES = create_member_group(
name='Comptes dédiés',
products=[
ID_PRODUIT_COMPTE_DEDIE,
]
)
# Adhérents : On crée d'abord les 2 groupes car on en a besoin pour
# définir les permissions (autrement dit pour créer les produits).
prestataires = 'Adhérents prestataires'
utilisateurs = 'Adhérents utilisateurs'
# @WARNING : avant c'etait DISABLED, sûrement parce que le jeu de tests utilisateurs
# était généré indépendamment de l'environnement (prod / dev / test) --> c'était un FIXME dans init_test_data.py
# ce problème étant réglé, on peut les autoriser sans crainte par défaut
ID_GROUPE_ADHERENTS_PRESTATAIRES = create_member_group(
name=prestataires,
initial_user_status='DISABLED',
)
ID_GROUPE_ADHERENTS_UTILISATEURS = create_member_group(
name=utilisateurs,
initial_user_status='DISABLED',
)
# Permissions pour les prestataires.
#On est plus permissif sur les droits d'accès : login / email / numero de compte... quitte à les enlever après
ID_PRODUIT_ADHERENTS_PRESTATAIRES = create_member_product(
name=prestataires,
my_profile_fields=[
'FULL_NAME',
'LOGIN_NAME',
'EMAIL',
'ACCOUNT_NUMBER',
'ADDRESS'
],
accessible_user_groups=[
ID_GROUPE_ADHERENTS_PRESTATAIRES,
ID_GROUPE_ADHERENTS_UTILISATEURS,
],
other_users_profile_fields={
'FULL_NAME': True,
'LOGIN_NAME': True,
'EMAIL': True,
'ACCOUNT_NUMBER': True,
},
user_account_type_id=ID_COMPTE_ADHERENT,
dashboard_actions=[
'ACCOUNT_INFO',
'PAYMENT_USER_TO_USER',
'PAYMENT_USER_TO_SYSTEM',
],
password_actions=[
'login',
# 'pin',
],
my_access_clients=[
ID_CLIENT_POINT_DE_VENTE_NFC,
ID_CLIENT_SMS,
ID_CLIENT_MAIN,
],
my_token_types=[
ID_TOKEN_CARTE_NFC,
],
system_payments=[
ID_TYPE_PAIEMENT_RECONVERSION_NUMERIQUE,
],
user_payments=[
ID_TYPE_PAIEMENT_VIREMENT_INTER_ADHERENT,
ID_TYPE_PAIEMENT_PAIEMENT_PAR_CARTE,
ID_TYPE_PAIEMENT_PAIEMENT_PAR_SMS,
],
scheduled_payments=[
'VIEW',
'CANCEL',
'PROCESS_INSTALLMENT'
],
recurring_payments=[
'VIEW',
'CANCEL'
],
receive_payments=[
ID_TYPE_PAIEMENT_PAIEMENT_PAR_CARTE,
],
)
assign_product_to_group(ID_PRODUIT_ADHERENTS_PRESTATAIRES,
ID_GROUPE_ADHERENTS_PRESTATAIRES)
# Permissions pour les utilisateurs.
ID_PRODUIT_ADHERENTS_UTILISATEURS = create_member_product(
name=utilisateurs,
my_profile_fields=[
'FULL_NAME',
'LOGIN_NAME',
'EMAIL',
'ACCOUNT_NUMBER',
'ADDRESS'
],
accessible_user_groups=[
ID_GROUPE_ADHERENTS_PRESTATAIRES,
ID_GROUPE_ADHERENTS_UTILISATEURS,
],
other_users_profile_fields={
'FULL_NAME': True,
'LOGIN_NAME': True,
'EMAIL': True,
'ACCOUNT_NUMBER': True,
},
user_account_type_id=ID_COMPTE_ADHERENT,
dashboard_actions=[
'ACCOUNT_INFO',
'PAYMENT_USER_TO_USER',
'PAYMENT_USER_TO_SYSTEM',
],
password_actions=[
'login',
# 'pin',
],
my_access_clients=[
ID_CLIENT_SMS,
ID_CLIENT_MAIN,
],
my_token_types=[
ID_TOKEN_CARTE_NFC,
],
user_payments=[
ID_TYPE_PAIEMENT_VIREMENT_INTER_ADHERENT,
ID_TYPE_PAIEMENT_PAIEMENT_PAR_CARTE,
ID_TYPE_PAIEMENT_PAIEMENT_PAR_SMS,
],
scheduled_payments=[
'VIEW',
'CANCEL',
'PROCESS_INSTALLMENT'
],
recurring_payments=[
'VIEW',
'CANCEL'
]
)
assign_product_to_group(ID_PRODUIT_ADHERENTS_UTILISATEURS,
ID_GROUPE_ADHERENTS_UTILISATEURS)
# Produit pour tous les groupes d'utilisateurs qui n'auront pas de
# compte.
ID_PRODUIT_UTILISATEURS_BASIQUES_SANS_COMPTE = create_member_product(
name='Utilisateurs basiques sans compte',
my_profile_fields=[
'FULL_NAME',
'LOGIN_NAME',
],
#@WARNING : y'a-t-il un intérêt de proposer une connexion à des utilisateurs sans compte ?
# password_actions=[
# 'login',
# ],
)
# Porteurs.
ID_GROUPE_PORTEURS = create_member_group(
name='Porteurs',
products=[
ID_PRODUIT_UTILISATEURS_BASIQUES_SANS_COMPTE,
]
)
# Adhérents sans compte.
ID_GROUPE_ADHERENTS_SANS_COMPTE = create_member_group(
name='Adhérents sans compte',
initial_user_status='DISABLED',
products=[
ID_PRODUIT_UTILISATEURS_BASIQUES_SANS_COMPTE,
]
)
all_user_groups = [
ID_GROUPE_BUREAUX_DE_CHANGE,
ID_GROUPE_BANQUES_DE_DEPOT,
ID_GROUPE_COMPTES_DEDIES,
ID_GROUPE_ADHERENTS_PRESTATAIRES,
ID_GROUPE_ADHERENTS_UTILISATEURS,
ID_GROUPE_PORTEURS,
ID_GROUPE_ADHERENTS_SANS_COMPTE,
]
# Définition des permissions.
# Il faut faire ça en dernier car nous avons besoin de tous les objets
# créés auparavant.
#
## Permissions pour le groupe "Administrateurs réseaux":
def get_group_id(web_services, name, nature):
r = requests.post(web_services + 'group/search',
headers=headers,
json={
'name': name,
'natures': nature,
})
check_request_status(r)
groups = r.json()['result']['pageItems']
for group in groups:
if group['name'] == name:
return group['id']
return None;
ID_GROUPE_NETWORK_ADMINS = get_group_id(
network_web_services,
'Network administrators' ,
'ADMIN_GROUP'
)
set_admin_group_permissions(
group_id=ID_GROUPE_NETWORK_ADMINS,
my_profile_fields=[
'FULL_NAME',
'LOGIN_NAME',
'EMAIL',
'ACCOUNT_NUMBER',
'ADDRESS',
],
password_actions=[
'login',
],
visible_transaction_fields=[],#all_transaction_fields,
my_access_clients = [ID_CLIENT_MAIN],
transfer_status_flows=[],#all_status_flows,
system_accounts=all_system_accounts,
system_to_system_payments=[ ID_TYPE_PAIEMENT_ENTREE_COFFRE_NUMERIQUE,ID_TYPE_PAIEMENT_SORTIE_COFFRE_NUMERIQUE ],#all_system_to_system_payments,
system_to_user_payments=all_system_to_user_payments,
chargeback_of_payments_to_system=all_payments_to_system,
accessible_user_groups=[
ID_GROUPE_ADHERENTS_PRESTATAIRES,
ID_GROUPE_ADHERENTS_UTILISATEURS
], #all_user_groups,
accessible_administrator_groups=[
ID_GROUPE_NETWORK_ADMINS,
],
user_profile_fields=[
'FULL_NAME',
'LOGIN_NAME',
'EMAIL',
'ACCOUNT_NUMBER',
'ADDRESS',
# ID_CHAMP_PERSO_UTILISATEUR_BDC,
],
change_group='MANAGE',
user_registration=True,
blocked_users_manage=True,
disabled_users='MANAGE',
removed_users='MANAGE',
user_password_actions=[
'login',
# 'pin',
],
user_channels_access='MANAGE',
user_token_types=[],#all_token_types,
user_access_clients=all_access_clients,
access_user_accounts=all_user_accounts,
payments_as_user_to_user=all_user_to_user_payments,
payments_as_user_to_system=all_user_to_system_payments,
payments_as_user_to_self=[],#all_user_to_self_payments,
user_scheduled_payments = ['VIEW','CANCEL','PROCESS_INSTALLMENT'],
user_recurring_payments = ['VIEW'],
chargeback_of_payments_to_user=all_payments_to_user
)
# Permissions pour le groupe "Gestion interne":
set_admin_group_permissions(
group_id=ID_GROUPE_GESTION_INTERNE,
my_profile_fields=[
'FULL_NAME',
'LOGIN_NAME',
],
password_actions=[
'login',
],
visible_transaction_fields=all_transaction_fields,
transfer_status_flows=all_status_flows,
system_accounts=all_system_accounts,
system_to_system_payments=all_system_to_system_payments,
system_to_user_payments=all_system_to_user_payments,
chargeback_of_payments_to_system=all_payments_to_system,
accessible_user_groups=all_user_groups,
accessible_administrator_groups=[
ID_GROUPE_OPERATEURS_BDC,
ID_GROUPE_GESTION_INTERNE,
],
user_profile_fields=[
'FULL_NAME',
'LOGIN_NAME',
'ACCOUNT_NUMBER',
'EMAIL',
ID_CHAMP_PERSO_UTILISATEUR_BDC,
],
change_group='MANAGE',
user_registration=True,
blocked_users_manage=True,
disabled_users='MANAGE',
removed_users='MANAGE',
user_password_actions=[
'login',
# 'pin',
],
user_token_types=all_token_types,
user_access_clients=all_access_clients,
access_user_accounts=all_user_accounts,
payments_as_user_to_user=all_user_to_user_payments,
payments_as_user_to_system=all_user_to_system_payments,
payments_as_user_to_self=all_user_to_self_payments,
chargeback_of_payments_to_user=all_payments_to_user
)
# Permissions pour le groupe "Opérateurs BDC":
set_admin_group_permissions(
group_id=ID_GROUPE_OPERATEURS_BDC,
my_profile_fields=[
'FULL_NAME',
'LOGIN_NAME',
ID_CHAMP_PERSO_UTILISATEUR_BDC,
],
password_actions=[
'login',
],
visible_transaction_fields=all_transaction_fields,
transfer_status_flows=[
ID_STATUS_FLOW_RAPPROCHEMENT,
ID_STATUS_FLOW_REMISE_A_ASSO,
],
system_accounts=[
ID_COMPTE_DE_TRANSIT,
ID_COMPTE_DES_BILLETS_EN_CIRCULATION,
ID_COMPTE_DE_DEBIT_EURO,
ID_COMPTE_DE_DEBIT_CURRENCY_NUMERIQUE,
],
system_to_user_payments=[
ID_TYPE_PAIEMENT_ENTREE_STOCK_BDC,
ID_TYPE_PAIEMENT_CHANGE_BILLETS_VERSEMENT_DES_EUROS,
ID_TYPE_PAIEMENT_RECONVERSION_BILLETS,
ID_TYPE_PAIEMENT_COTISATION_EN_EURO,
ID_TYPE_PAIEMENT_COTISATION_EN_MLC,
ID_TYPE_PAIEMENT_VENTE_EN_EURO,
ID_TYPE_PAIEMENT_VENTE_EN_MLC,
ID_TYPE_PAIEMENT_REGUL_DEPOT_INSUFFISANT,
ID_TYPE_PAIEMENT_CHANGE_NUMERIQUE_EN_BDC,
ID_TYPE_PAIEMENT_DEPOT_DE_BILLETS,
ID_TYPE_PAIEMENT_CREDIT_DU_COMPTE,
],
accessible_user_groups=all_user_groups,
accessible_administrator_groups=[
ID_GROUPE_OPERATEURS_BDC,
],
user_profile_fields=[
'FULL_NAME',
'LOGIN_NAME',
'ACCOUNT_NUMBER',
'EMAIL',
],
user_registration=True,
# disabled_users='VIEW',
access_user_accounts=[
ID_STOCK_DE_BILLETS_BDC,
ID_CAISSE_EURO_BDC,
ID_CAISSE_CURRENCY_BDC,
ID_RETOURS_CURRENCY_BDC,
ID_BANQUE_DE_DEPOT,
ID_COMPTE_ADHERENT,
],
payments_as_user_to_user=[
ID_TYPE_PAIEMENT_DEPOT_EN_BANQUE,
ID_TYPE_PAIEMENT_BANQUE_VERS_CAISSE_EURO_BDC,
ID_TYPE_PAIEMENT_CAISSE_EURO_BDC_VERS_BANQUE,
],
payments_as_user_to_system=[
ID_TYPE_PAIEMENT_SORTIE_STOCK_BDC,
ID_TYPE_PAIEMENT_SORTIE_CAISSE_CURRENCY_BDC,
ID_TYPE_PAIEMENT_SORTIE_RETOURS_CURRENCY_BDC,
ID_TYPE_PAIEMENT_REGUL_DEPOT_EXCESSIF,
ID_TYPE_PAIEMENT_REMISE_EUROS_EN_CAISSE,
ID_TYPE_PAIEMENT_BANQUE_VERS_COMPTE_DE_DEBIT,
ID_TYPE_PAIEMENT_RETRAIT_DE_BILLETS,
ID_TYPE_PAIEMENT_RETRAIT_DU_COMPTE,
],
)
# Permissions pour le groupe "Anonyme":
set_admin_group_permissions(
group_id=ID_GROUPE_ANONYME,
my_profile_fields=[
'FULL_NAME',
'LOGIN_NAME',
],
password_actions=[
'login',
],
visible_transaction_fields=[
ID_CHAMP_PERSO_PAIEMENT_NUMERO_TRANSACTION_BANQUE,
],
system_accounts=[
ID_COMPTE_DE_DEBIT_EURO,
ID_COMPTE_DE_DEBIT_CURRENCY_NUMERIQUE,
],
system_to_user_payments=[
ID_TYPE_PAIEMENT_CHANGE_NUMERIQUE_EN_LIGNE_VERSEMENT_DES_EUROS,
ID_TYPE_PAIEMENT_CHANGE_NUMERIQUE_EN_LIGNE_VERSEMENT_DES_MLC,
ID_TYPE_PAIEMENT_CREDIT_DU_COMPTE
],
access_user_accounts=[ID_COMPTE_ADHERENT],
accessible_user_groups=[
ID_GROUPE_ADHERENTS_PRESTATAIRES,
ID_GROUPE_ADHERENTS_UTILISATEURS,
ID_GROUPE_ADHERENTS_SANS_COMPTE,
],
user_profile_fields=[
'ACCOUNT_NUMBER',
],
# change_group='MANAGE',
disabled_users='MANAGE',
user_scheduled_payments = ['VIEW'],
user_recurring_payments = ['VIEW'],
# user_password_actions=[
# 'login',
# ],
)
########################################################################
# Création des utilisateurs pour les comptes dédiés.
#
def create_user(group, name, login, password=None):
logger.info('Création de l\'utilisateur "%s"...', name)
json_query={
'group': group,
'name': name,
'username': login,
'skipActivationEmail': True,
}
if password != None:
json_query[0]['passwords'] = {
'assign': True ,
'type': 'login',
'value': password,
'confirmationValue': password
}
r = requests.post(network_web_services + 'user/register',
headers=headers,
json=json_query
)
check_request_status(r)
user_id = r.json()['result']['user']['id']
logger.debug('user_id = %s', user_id)
add_constant('users', name, user_id)
return user_id
create_user(
group=ID_GROUPE_COMPTES_DEDIES,
name='Compte dédié ' + LOCAL_CURRENCY_INTERNAL_NAME +' billet',
login='CD_BILLET',
)
create_user(
group=ID_GROUPE_COMPTES_DEDIES,
name='Compte dédié ' + LOCAL_CURRENCY_INTERNAL_NAME +' numérique',
login='CD_NUMERIQUE',
)
########################################################################
# Récupération de la liste des types de mot de passe.
r = requests.get(network_web_services + 'passwordType/list',
headers=headers)
for passwordType in r.json()['result']:
add_constant('password_types', passwordType['name'], passwordType['id'])
########################################################################
# On écrit dans un fichier toutes les constantes nécessaires à l'API,
# après les avoir triées.
logger.debug('Constantes :\n%s', constants_by_category)
constants_file = open('cyclos_constants_' + ENV +'.yml', 'w')
for category in sorted(constants_by_category.keys()):
constants_file.write(category + ':\n')
constants = constants_by_category[category]
for name in sorted(constants.keys()):
constants_file.write(' ' + name + ': ' + constants[name] + '\n')
constants_file.close()