Commit be2d2b5b by Javier

Versión Actualizada

parent 71216407
import mariadb
DB_CREDENTIALS = {
'host': '192.168.2.220',
'user': 'api-mbilling',
'password': 'mbillingmbilling',
'port': 3306,
'database': 'mya2billing'
}
def account_data(callerid: str) -> dict:
with mariadb.connect(**DB_CREDENTIALS) as cnx:
with cnx.cursor() as cursor:
headers = ['account', 'secret', 'credit']
cursor.execute(
'SELECT car.username, car.uipass, round(car.credit, 2) credit FROM cc_callerid cid\
INNER JOIN cc_card car ON car.id=cid.id_cc_card WHERE cid.cid=?',
(callerid,)
)
data = cursor.fetchone()
return dict(zip(headers, data)) if data else None
from decimal import Decimal
from typing import Tuple from typing import Tuple
import typer import typer
from mbilling.functions import MagnusCommandError, active_users, fully_ported_clis, get_cdrs, add_balance from mbilling.functions import MagnusCommandError, SipAccount, active_users, fully_ported_users, get_sip_accounts, get_cdrs, add_balance, get_user
import time import time
import pyodbc import pyodbc
import os import os
from datetime import timedelta, datetime from datetime import timedelta, datetime
from a2billing import a2billing
# Credenciales SQL Server # Credenciales SQL Server
sql_server_hostname = "192.168.2.200" sql_server_hostname = "192.168.2.200"
sql_server_database = "bdd_wifi" sql_server_database = "bdd_wifi"
...@@ -28,62 +31,135 @@ app = typer.Typer(chain=True) ...@@ -28,62 +31,135 @@ app = typer.Typer(chain=True)
# Funciones Auxiliares # Funciones Auxiliares
def new_plataform_clis() -> 'list[str]': def update_sip_accounts() -> 'Tuple[int,int]':
"""Obtiene los CLI activos en la Magnus Billing """Sincroniza el estado de las Cuentas SIP
Es posible que algunos números estén en Magnus Billing pero\
la gestión de su saldo y llamadas salientes se realize aún\
desde A2Billing por alguna razón. Estos números no se deben\
tener en cuenta en la actualización de Saldo y valores, por lo\
que con está función obtendremos los números que debemos actualizar.
Returns: Returns:
list[str]: Listado de números que podemos actualizar. Tuple[int,int]: Tupla que contiene el número de cuentas SIP y DIDs
""" """
sip_accounts_updated = 0
did_accounts_updated = 0
with pyodbc.connect(SQL_SERVER_CNX_STRING) as cnx: with pyodbc.connect(SQL_SERVER_CNX_STRING) as cnx:
with cnx.cursor() as cursor: with cnx.cursor() as cursor:
cursor.execute( with typer.progressbar(get_sip_accounts(), label="Sincronizando Cuentas") as sips:
"SELECT DDI FROM TB_ServicioFijo WHERE FechaBaja IS NULL AND NuevaPlataforma = 1") for sip in sips:
active_dids = [d[0] for d in cursor.fetchall()] # Llamadas Salientes por Nueva Plataforma
if sip.credit == 0.0:
cursor.execute(
"SELECT NuevaPlataforma FROM [bdd_wifi].[dbo].[TB_ServicioFijo]\
WHERE DDI IN (?,?) AND NuevaPlataforma=1",
(sip.callerid, sip.account)
)
nueva_plataforma = 1 if cursor.fetchone() else 0
else:
nueva_plataforma = 1
return active_dids cursor.execute(
"UPDATE [bdd_wifi].[dbo].[TB_ServicioFijo]\
SET SaldoActual=?, Activo=?, TarifaPlana=?, Pospago=?, IdTarifa=?, UsuarioEXT=?,\
ClaveEXT=?, NuevaPlataforma=? WHERE DDI=? AND FechaBaja is NULL",
(sip.credit, sip.active, sip.offer != 0, sip.postpaid, sip.plan,
sip.callerid if sip.account == sip.callerid else None,
sip.secret if sip.account == sip.callerid else None, nueva_plataforma,
sip.callerid)
)
if sip.account == sip.callerid:
sip_accounts_updated = sip_accounts_updated + 1
else:
did_accounts_updated = did_accounts_updated + 1
def new_plataform_activate(*cli: str): return sip_accounts_updated, did_accounts_updated
"""Agrega al CLI a Nueva Plataforma
Modifica el Programa de Facturación para indicar que este CLI está\
completamente portado a la Nueva Plataforma. Los números con este indicador\
serán aquellos que podrán ser modificados por este programa.
""" def activate_new_plataform():
"""Activa el Check NuevaPlataforma en las Cuentas SIP cuyas llamadas\
salgan por MagnusBilling"""
with pyodbc.connect(SQL_SERVER_CNX_STRING) as cnx: with pyodbc.connect(SQL_SERVER_CNX_STRING) as cnx:
with cnx.cursor() as cursor: with cnx.cursor() as cursor:
for c in cli: for sip, account in fully_ported_users():
account = account if sip == account else None
cursor.execute( cursor.execute(
"UPDATE TB_ServicioFijo SET NuevaPlataforma = 1 WHERE DDI = ?", ( 'UPDATE [bdd_wifi].[dbo].[TB_ServicioFijo] SET NuevaPlataforma=1 WHERE DDI=?',
c,) (sip,)
) )
cursor.execute(
'UPDATE [bdd_wifi].[dbo].[TB_ServicioFijo] SET ClaveEXT=NULL, SaldoActual=0.0,\
TarifaPlana=0, Pospago=0, IdTarifa=0 WHERE UsuarioEXT is NULL'
)
cnx.commit()
def update_target_clis() -> 'list[str]': def perform_migration():
"""Obtiene el listado de CLIs que deben ser Actualizados. with pyodbc.connect(SQL_SERVER_CNX_STRING) as cnx:
with cnx.cursor() as cursor:
migration_targets = cursor.execute(
'SELECT [DDI] FROM [bdd_wifi].[dbo].[TB_ServicioFijo]\
WHERE NuevaPlataforma=1 AND UsuarioEXT != DDI'
)
Los números que han de ser actualizados deben estar en la nueva plataforma\ for ddi in migration_targets.fetchall():
y estar activos en la Magnus Billing. Esta función busca aquellos CLIs\ ddi = ddi[0]
que cumplen ambas condiciones y deben ser tenidos en cuenta a la hora\ # Obtención Cuenta MagnusBilling
de las actualizaciones de las cuentas. user = get_user(ddi)
a2billing_user = a2billing.account_data(ddi)
if user['sip'] == user['username']:
cursor.execute(
'UPDATE [bdd_wifi].[dbo].[TB_ServicioFijo] SET CuentaA2Billing=?,\
UsuarioEXT=?, ClaveEXT=?, Activo=?, TarifaPlana=?,Pospago=?,\
IdTarifa=? WHERE DDI=?',
(a2billing_user['account'] if a2billing_user else None, user['username'],
user['password'], user['active'], user['offer'] != 0, user['postpaid'],
user['plan'], ddi)
)
cursor.execute(
'UPDATE [bdd_wifi].[dbo].[TB_Recargas] SET Cuenta=? WHERE Cuenta=?',
(user['username'], a2billing_user['account'])
)
print(user['username'])
else:
cursor.execute(
'UPDATE [bdd_wifi].[dbo].[TB_ServicioFijo] SET CuentaA2Billing=NULL,\
UsuarioEXT=NULL, ClaveEXT=NULL, Activo=?, TarifaPlana=0, Pospago=0,\
IdTarifa=0, SaldoActual=0.0 WHERE DDI=?',
(user['active'], ddi)
)
cnx.commit()
def new_plataform_clis() -> 'list[str]':
"""Obtiene los CLI activos en la Magnus Billing
Es posible que algunos números estén en Magnus Billing pero\
la gestión de su saldo y llamadas salientes se realize aún\
desde A2Billing por alguna razón. Estos números no se deben\
tener en cuenta en la actualización de Saldo y valores, por lo\
que con está función obtendremos los números que debemos actualizar.
Returns: Returns:
list[str]: Listado de CLIs a Actualizar. list[str]: Listado de números que podemos actualizar.
""" """
return list(set(fully_ported_clis()) & set(new_plataform_clis())) with pyodbc.connect(SQL_SERVER_CNX_STRING) as cnx:
with cnx.cursor() as cursor:
cursor.execute(
"SELECT DDI FROM TB_ServicioFijo WHERE FechaBaja IS NULL AND NuevaPlataforma = 1")
active_dids = [d[0] for d in cursor.fetchall()]
return active_dids
def get_last_updated_cdr(account: str = None, only_post_payment: bool = True) -> dict: def get_last_updated_cdr(*account: str) -> dict:
"""Obtiene la fecha de la última actualización del CDR de una Cuenta """Obtiene la fecha de la última actualización del CDR de una Cuenta
Args: Args:
...@@ -94,88 +170,73 @@ def get_last_updated_cdr(account: str = None, only_post_payment: bool = True) -> ...@@ -94,88 +170,73 @@ def get_last_updated_cdr(account: str = None, only_post_payment: bool = True) ->
dict: _description_ dict: _description_
""" """
last_update = {}
with pyodbc.connect(SQL_SERVER_CNX_STRING) as cnx: with pyodbc.connect(SQL_SERVER_CNX_STRING) as cnx:
with cnx.cursor() as cursor: with cnx.cursor() as cursor:
# Construcción de la Cadena for ddi in account:
query = "SELECT DDI FROM [bdd_wifi].[dbo].[TB_ServicioFijo] WHERE NuevaPlataforma=1"
query = query + " AND Pospago = 1" if only_post_payment else query
query = query + f" AND DDI = {account}" if account else query
# Obtención de Números a Actualizar
cursor.execute(query)
cdr_last_updated = {}
for ddi in cursor.fetchall():
cursor.execute( cursor.execute(
'SELECT TOP 1 fecha FROM bdd_wifi.dbo.TB_OMV_CDR_Cliente WHERE DDi = ? ORDER BY fecha DESC', 'SELECT TOP 1 [Fecha] FROM[bdd_wifi].[dbo].[TB_OMV_CDR_Cliente]\
(ddi[0]) WHERE DDi=? ORDER BY Fecha DESC', (ddi,))
) last_update[ddi] = cursor.fetchval()
last_updated = cursor.fetchone()
cdr_last_updated[ddi[0]
] = last_updated[0] if last_updated else None
return cdr_last_updated return last_update
def update_balance(target_clis: list[str]) -> Tuple[int, int]: def update_balance() -> Tuple[int, Decimal]:
"""Actualiza el Saldo de las Cuentas SIP """Actualiza el Saldo de las Cuentas SIP
""" """
# Cuentas Actualizadas accounts = 0
updated = 0 balance = Decimal('0.0')
non_updated = 0
# Actualización de Balance en Programa de Facturación # Actualización de Balance en Programa de Facturación
with pyodbc.connect(SQL_SERVER_CNX_STRING) as cnx: with pyodbc.connect(SQL_SERVER_CNX_STRING) as cnx:
with cnx.cursor() as cursor: with cnx.cursor() as cursor:
with typer.progressbar(active_users(), label="Actualizando Balance") as progress: with typer.progressbar(active_users(), label="Actualizando Balance") as progress:
for sip_account in progress: for sip_account in progress:
if sip_account['username'] in target_clis: # Cálculo de Parámetros
# Cálculo de Parámetros
flat_rate = sip_account['offer'] if sip_account['plan'] == TARIFA_PLANA_ID else None
credit = 999.00 if sip_account['credit'] <= 0 and sip_account['postpaid'] == True else round(
sip_account['credit'], 2)
# Si la cuenta es emisora de llamadas, añadimos ClaveEXT
if sip_account['credit'] > 0:
cursor.execute(
"""UPDATE [bdd_wifi].[dbo].[TB_ServicioFijo]
SET SaldoActual=?, Activo=?, TarifaPlana=?, Pospago=?, IdTarifa=?, UsuarioEXT=?,
ClaveEXT=? WHERE DDI=? AND FechaBaja is NULL""",
(credit, sip_account['active'],
flat_rate, sip_account['postpaid'], sip_account['plan'], sip_account['username'],
sip_account['password'], sip_account['username'])
)
else: if sip_account['username'] != sip_account['sip']:
cursor.execute( credit = 0.0
"""UPDATE [bdd_wifi].[dbo].[TB_ServicioFijo] elif sip_account['credit'] <= 0.0 and sip_account['postpaid'] == True:
SET SaldoActual=?, Activo=?, TarifaPlana=?, Pospago=?, IdTarifa=? credit = 999.00
WHERE DDI=? AND FechaBaja is NULL""", else:
(credit, sip_account['active'], credit = round(sip_account['credit'], 2)
flat_rate, sip_account['postpaid'], sip_account['plan'], sip_account['username'])
)
updated = updated + 1 # Si la cuenta es emisora de llamadas, añadimos ClaveEXT
cnx.commit() cursor.execute(
"UPDATE [bdd_wifi].[dbo].[TB_ServicioFijo] SET SaldoActual=? WHERE DDI=?",
(credit, sip_account['sip'])
)
cnx.commit()
else: accounts += 1
non_updated = non_updated + 1 balance += sip_account['credit']
return updated, non_updated cursor.execute(
"UPDATE [bdd_wifi].[dbo].[TB_ServicioFijo] SET SaldoActual=0.0 WHERE UsuarioEXT is NULL")
cnx.commit()
return accounts, balance
def add_cdrs(accounts: list[dict]) -> 'list[dict]': def add_cdrs(accounts: list[dict]) -> 'list[dict]':
# Obtención de Parámetros
sip_accounts = get_sip_accounts(only_postpaid=True)
last_update = get_last_updated_cdr(*[sip.callerid for sip in sip_accounts])
cdrs = [] cdrs = []
for account in (accounts.keys()):
cdrs.extend(get_cdrs(phone_number=account, since=accounts[account]))
# Carga en Memoria de CDRs
for account in sip_accounts:
since = last_update[account.callerid] if account.callerid in last_update.keys() else None
cdrs.extend(get_cdrs(phone_number=account.callerid, since=since))
# Almacenamiento en Servidor SQL
with typer.progressbar(cdrs, label='Sincronizando CDRs') as cdr_data: with typer.progressbar(cdrs, label='Sincronizando CDRs') as cdr_data:
with pyodbc.connect(SQL_SERVER_CNX_STRING) as cnx: with pyodbc.connect(SQL_SERVER_CNX_STRING) as cnx:
with cnx.cursor() as cursor: with cnx.cursor() as cursor:
for cdr in cdr_data: for cdr in cdr_data:
cursor.execute( cursor.execute(
'INSERT INTO bdd_wifi.dbo.TB_OMV_CDR_Cliente (Tipo, DDi, Fecha, \ 'INSERT INTO bdd_wifi.dbo.TB_OMV_CDR_Cliente (Tipo, DDi, Fecha, \
...@@ -205,7 +266,7 @@ def process_refills() -> Tuple[int, float]: ...@@ -205,7 +266,7 @@ def process_refills() -> Tuple[int, float]:
# Obtención de Recargas Pendientes # Obtención de Recargas Pendientes
pending_refills = cnx.execute( pending_refills = cnx.execute(
'SELECT r.ID, f.DDI, r.Importe, r.Automatica \ 'SELECT r.ID, f.DDI, r.Importe, r.Automatica, f.NuevaPlataforma \
FROM [bdd_wifi].[dbo].[TB_Recargas] r \ FROM [bdd_wifi].[dbo].[TB_Recargas] r \
INNER JOIN [bdd_wifi].[dbo].[TB_ServicioFijo] f ON f.UsuarioEXT=r.Cuenta \ INNER JOIN [bdd_wifi].[dbo].[TB_ServicioFijo] f ON f.UsuarioEXT=r.Cuenta \
WHERE Procesado=0' WHERE Procesado=0'
...@@ -216,18 +277,19 @@ def process_refills() -> Tuple[int, float]: ...@@ -216,18 +277,19 @@ def process_refills() -> Tuple[int, float]:
for refill in refills: for refill in refills:
try: try:
# Generación de Descripción # Generación de Descripción
description = 'Recarga Automática ID ' if refill[3] else 'Recarga Manual ID ' if refill[4]:
description = description + str(refill[0]) description = 'Recarga Automática ID ' if refill[3] else 'Recarga Manual ID '
description = description + str(refill[0])
# Insercción de Balance
add_balance( # Insercción de Balance
phone_number=refill[1], add_balance(
quantity=refill[2], phone_number=refill[1],
description=description quantity=refill[2],
) description=description
)
total_refills = total_refills + 1 total_refills = total_refills + 1
amount = amount + refill[2] amount = amount + refill[2]
except MagnusCommandError: except MagnusCommandError:
# Número no registrado en Magnus # Número no registrado en Magnus
...@@ -245,17 +307,7 @@ def process_refills() -> Tuple[int, float]: ...@@ -245,17 +307,7 @@ def process_refills() -> Tuple[int, float]:
@app.command() @app.command()
def update_plataform(): def update(account: str = typer.Argument(default=None, )):
"""Actualiza las CLIs agregados a la Nueva Plataforma
"""
typer.echo('Actualizando Líneas en Nueva Plataforma.')
new_plataform_activate(*fully_ported_clis())
typer.echo('Actualización finalizada.')
@app.command()
def update_account(account: str = typer.Argument(default=None, )):
"""Actualiza las cuentas SIP """Actualiza las cuentas SIP
Sincroniza de MagnusBilling en el programa de facturación. Sincroniza de MagnusBilling en el programa de facturación.
...@@ -264,19 +316,7 @@ def update_account(account: str = typer.Argument(default=None, )): ...@@ -264,19 +316,7 @@ def update_account(account: str = typer.Argument(default=None, )):
account (str, optional): Cuenta Objetivo, por defecto todas. Defaults to typer.Argument(default=None, ). account (str, optional): Cuenta Objetivo, por defecto todas. Defaults to typer.Argument(default=None, ).
""" """
# Obtiene los números completamente portados. update_sip_accounts()
target_clis = update_target_clis() if not account else [account]
# Líneas Actualizadas
updated = 0
non_updated = 0
updated, non_updated = update_balance(target_clis)
msg = "Se han actualizado "
msg = msg + typer.style(updated, fg=typer.colors.GREEN, bold=True)
msg = msg + f" de un total de {updated + non_updated} líneas."
typer.echo(msg)
@app.command() @app.command()
...@@ -312,37 +352,50 @@ def synchronize(): ...@@ -312,37 +352,50 @@ def synchronize():
""" """
start_time = datetime.now() start_time = datetime.now()
# Verificación de SIP en Nueva Plataforma msg = '\nActualización Finalizada,\n'
new_plataform_activate(*fully_ported_clis())
typer.echo('Verificación de Plataformas Finalizada') # Sincronización de Cuentas
sip_accounts, did_accounts = update_sip_accounts()
msg += f'\t- Se han actualizado {typer.style(sip_accounts, fg=typer.colors.GREEN, bold=True)} CLIs y '
msg += f'{typer.style(did_accounts, fg=typer.colors.BRIGHT_YELLOW, bold=True)} DIDs.'
# Recargas # Recargas
total_refills, amount = process_refills() total_refills, amount = process_refills()
msg = f"Se han procesado " msg += f"\n\t- Se han procesado {typer.style(total_refills, fg=typer.colors.GREEN, bold=True)} "
msg = msg + typer.style(total_refills, fg=typer.colors.GREEN, bold=True)e msg += f"recargas con un importe total de {typer.style(f'{amount}€', fg=typer.colors.GREEN, bold=True)}"
msg = msg + " recargas con un importe total de "
msg = msg + typer.style(f'{amount}€', fg=typer.colors.GREEN, bold=True)
typer.echo(msg)
# Actualización de Estado # Actualización de Estado
updated, non_updated = update_balance(update_target_clis()) accounts, balance = update_balance()
msg = "Se han actualizado " msg += f"\n\t- Se ha actualizado el saldo de {accounts} cuentas, con un saldo total de {typer.style(f'{round(balance,2)}€', fg=typer.colors.GREEN, bold=True)}€."
msg = msg + typer.style(updated, fg=typer.colors.GREEN, bold=True)
msg = msg + f" de un total de {updated + non_updated} líneas."
typer.echo(msg)
# Actualización de CDRs # Actualización de CDRs
accounts = get_last_updated_cdr() accounts = get_last_updated_cdr()
cdrs = add_cdrs(accounts) cdrs = add_cdrs(accounts)
msg = f"Se han sincronizado un total de " msg += f"\n\t- Se han sincronizado un total de {typer.style(len(cdrs), fg=typer.colors.GREEN, bold=True)} "
msg = msg + typer.style(len(cdrs), fg=typer.colors.GREEN, bold=True) msg += f"llamadas de un total de {typer.style(len(accounts), fg=typer.colors.GREEN, bold=True)} líneas telefónicas."
msg = msg + " llamadas de un total de " msg += f'\n\nSincronización Finalizada en {round((datetime.now() - start_time).total_seconds(),2)} segundos.'
msg = msg + typer.style(len(accounts), fg=typer.colors.GREEN, bold=True)
msg = msg + " líneas telefónicas."
typer.echo(msg) typer.echo(msg)
typer.echo(
f'Sincronización Finalizada en {round((datetime.now() - start_time).total_seconds(),2)} segundos.') @app.command()
def restore():
with pyodbc.connect(SQL_SERVER_CNX_STRING) as cnx:
with cnx.cursor() as cursor:
cursor.execute(
'UPDATE [bdd_wifi].[dbo].[TB_ServicioFijo] SET UsuarioEXT=CuentaA2Billing, NuevaPlataforma=0 WHERE NuevaPlataforma=1'
)
cnx.commit()
@app.command()
def test():
activate_new_plataform()
perform_migration()
update_balance()
import_cdr()
if __name__ == "__main__": if __name__ == "__main__":
......
from decimal import Decimal
import subprocess import subprocess
import pathlib import pathlib
import re import re
...@@ -23,6 +24,20 @@ DB_CREDENTIALS = { ...@@ -23,6 +24,20 @@ DB_CREDENTIALS = {
} }
class SipAccount:
def __init__(self, callerid: str, account: str, secret: str,
credit: float, plan: int, offer: int, active: bool, postpaid: bool) -> None:
self.callerid = callerid
self.account = account
self.secret = secret
self.credit = credit
self.plan = plan
self.offer = offer
self.active = active
self.postpaid = postpaid
class MagnusCommandError(Exception): class MagnusCommandError(Exception):
def __init__(self, *args: object, ) -> None: def __init__(self, *args: object, ) -> None:
...@@ -110,7 +125,7 @@ def _create_did(phone_number: str): ...@@ -110,7 +125,7 @@ def _create_did(phone_number: str):
raise MagnusCommandError(result.decode('utf-8')) raise MagnusCommandError(result.decode('utf-8'))
def _update_payment(phone_number: str, postpay: bool = False, credit: float = 0.0): def _update_payment(phone_number: str, postpay: bool = False, credit: Decimal = Decimal('0.0')):
with mariadb.connect(**DB_CREDENTIALS) as cnx: with mariadb.connect(**DB_CREDENTIALS) as cnx:
with cnx.cursor() as cursor: with cnx.cursor() as cursor:
...@@ -156,7 +171,7 @@ def create_user(phone_number: str, name: str, surname: str, password: str = None ...@@ -156,7 +171,7 @@ def create_user(phone_number: str, name: str, surname: str, password: str = None
return password return password
def add_balance(phone_number: str, quantity: float, tax: float = 0.21, description: str = 'Recarga Automática'): def add_balance(phone_number: str, quantity: Decimal, tax: Decimal = Decimal('0.21'), description: str = 'Recarga Automática'):
"""Añade saldo a una cuenta SIP """Añade saldo a una cuenta SIP
Args: Args:
...@@ -193,14 +208,17 @@ def get_user(phone_number: str) -> dict: ...@@ -193,14 +208,17 @@ def get_user(phone_number: str) -> dict:
with mariadb.connect(**DB_CREDENTIALS) as cnx: with mariadb.connect(**DB_CREDENTIALS) as cnx:
with cnx.cursor() as cursor: with cnx.cursor() as cursor:
headers = ['username', 'password', 'host', 'credit', headers = ['sip','username', 'password', 'host', 'credit',
'firstname', 'lastname', 'plan', 'offer'] 'firstname', 'lastname', 'plan', 'offer',
'active', 'postpaid']
cursor.execute( cursor.execute(
"""SELECT u.username, s.secret password, s.host, u.credit, u.firstname, u.lastname, p.id plan, o.id offer FROM mbilling.pkg_user u 'SELECT s.name, u.username, s.secret password, s.host, u.credit, u.firstname,\
INNER JOIN mbilling.pkg_plan p ON u.id_plan=p.id u.lastname, p.id plan, IFNULL(o.id, 0) offer, u.active active, u.typepaid\
LEFT JOIN mbilling.pkg_offer o ON u.id_offer=o.id FROM mbilling.pkg_user u\
INNER JOIN mbilling.pkg_sip s ON u.username=s.name INNER JOIN mbilling.pkg_plan p ON u.id_plan=p.id\
WHERE username=?""", LEFT JOIN mbilling.pkg_offer o ON u.id_offer=o.id\
INNER JOIN mbilling.pkg_sip s ON u.id=s.id_user\
WHERE s.name=?',
(phone_number,) (phone_number,)
) )
...@@ -209,7 +227,7 @@ def get_user(phone_number: str) -> dict: ...@@ -209,7 +227,7 @@ def get_user(phone_number: str) -> dict:
return dict(zip(headers, query)) if query else None return dict(zip(headers, query)) if query else None
def fully_ported_clis() -> 'list[str]': def fully_ported_users() -> 'list[tuple]':
"""Devuelve los CLI completamente portados a MBilling. """Devuelve los CLI completamente portados a MBilling.
Algunos usuarios pueden recibir llamadas en MB pero realizar la salida\ Algunos usuarios pueden recibir llamadas en MB pero realizar la salida\
...@@ -224,17 +242,16 @@ def fully_ported_clis() -> 'list[str]': ...@@ -224,17 +242,16 @@ def fully_ported_clis() -> 'list[str]':
with mariadb.connect(**DB_CREDENTIALS) as cnx: with mariadb.connect(**DB_CREDENTIALS) as cnx:
with cnx.cursor() as cursor: with cnx.cursor() as cursor:
cursor.execute( cursor.execute(
""" 'SELECT s.name cli, u.username account FROM mbilling.pkg_user u\
SELECT username cli FROM mbilling.pkg_user u INNER JOIN mbilling.pkg_cdr c ON c.callerid = u.username\
INNER JOIN mbilling.pkg_cdr c ON c.callerid = u.username INNER JOIN mbilling.pkg_trunk t ON c.id_trunk = t.id\
INNER JOIN mbilling.pkg_trunk t ON c.id_trunk = t.id INNER JOIN mbilling.pkg_sip s ON s.id_user = u.id\
WHERE c.id_trunk is not NULL AND t.trunkcode != 'a2billing' WHERE c.id_trunk is not NULL AND t.trunkcode != \'a2billing\' AND u.active=1\
GROUP BY username; GROUP BY s.name ORDER BY u.username')
""")
query = [cli[0] for cli in cursor.fetchall()] data = cursor.fetchall()
return query return data
def active_users() -> 'list[dict]': def active_users() -> 'list[dict]':
...@@ -244,25 +261,14 @@ def active_users() -> 'list[dict]': ...@@ -244,25 +261,14 @@ def active_users() -> 'list[dict]':
list[dict]: Listado de Usuarios y sus Datos list[dict]: Listado de Usuarios y sus Datos
""" """
with mariadb.connect(**DB_CREDENTIALS) as cnx: accounts = []
with cnx.cursor() as cursor: for account in fully_ported_users():
headers = ['username', 'password', 'host', 'credit', accounts.append(get_user(account[0]))
'firstname', 'lastname', 'plan', 'offer', 'active', 'postpaid']
cursor.execute(
"""SELECT u.username, s.secret password, s.host, u.credit, u.firstname, u.lastname,\
p.id plan_id, o.id offer_id, u.active, u.typepaid
FROM mbilling.pkg_user u
INNER JOIN mbilling.pkg_plan p ON u.id_plan=p.id
INNER JOIN mbilling.pkg_sip s ON u.username=s.name
LEFT JOIN mbilling.pkg_offer o ON u.id_offer=o.id"""
)
query = [dict(zip(headers, account)) return accounts
for account in cursor.fetchall()]
return query
def get_cdrs(phone_number : str, since : datetime = None, upto : datetime = None) -> 'list[dict]': def get_cdrs(phone_number: str, since: datetime = None, upto: datetime = None) -> 'list[dict]':
"""Obtiene los CDRs de una Línea """Obtiene los CDRs de una Línea
Args: Args:
...@@ -278,7 +284,8 @@ def get_cdrs(phone_number : str, since : datetime = None, upto : datetime = None ...@@ -278,7 +284,8 @@ def get_cdrs(phone_number : str, since : datetime = None, upto : datetime = None
with cnx.cursor() as cursor: with cnx.cursor() as cursor:
# Se eliminan llamadas a 016 # Se eliminan llamadas a 016
cursor.execute('DELETE FROM mbilling.pkg_cdr WHERE calledstation IN (\'016\', \'34016\')') cursor.execute(
'DELETE FROM mbilling.pkg_cdr WHERE calledstation IN (\'016\', \'34016\')')
# Carga de CDRs # Carga de CDRs
if upto and since: if upto and since:
...@@ -313,8 +320,33 @@ def get_cdrs(phone_number : str, since : datetime = None, upto : datetime = None ...@@ -313,8 +320,33 @@ def get_cdrs(phone_number : str, since : datetime = None, upto : datetime = None
data = cursor.fetchall() data = cursor.fetchall()
cdr = [] cdr = []
headers = ['callerid', 'destination', 'description', 'timestamp', 'duration', 'price', 'cost'] headers = ['callerid', 'destination', 'description',
'timestamp', 'duration', 'price', 'cost']
for line in data: for line in data:
cdr.append(dict(zip(headers, line))) cdr.append(dict(zip(headers, line)))
return cdr return cdr
def get_sip_accounts(only_postpaid : bool = False) -> 'list[SipAccount]':
"""Obtiene todas las cuentas SIPs de MagnusBilling
Returns:
list[SipAccount]: Listado de las Cuentas
"""
query = "SELECT s.callerid sip, u.username acc, s.secret secret, round(u.credit, 2) credit, u.id_plan plan,\
IFNULL(u.id_offer, 0) offer, u.active active, u.typepaid postpaid\
FROM mbilling.pkg_sip s\
INNER JOIN mbilling.pkg_user u ON u.id=s.id_user\
WHERE s.callerid > ''"
if only_postpaid:
query += ' AND u.typepaid=1'
with mariadb.connect(**DB_CREDENTIALS) as cnx:
with cnx.cursor() as cursor:
cursor.execute(query)
sip_data = cursor.fetchall()
return [SipAccount(*sip) for sip in sip_data]
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment