Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
S
scrapper-portabilidad
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
2
Issues
2
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Javier
scrapper-portabilidad
Commits
be2d2b5b
Commit
be2d2b5b
authored
May 05, 2022
by
Javier
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Versión Actualizada
parent
71216407
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
290 additions
and
181 deletions
+290
-181
__init__.py
a2billing/__init__.py
+0
-0
a2billing.py
a2billing/a2billing.py
+24
-0
cli.py
cli.py
+196
-143
functions.py
mbilling/functions.py
+70
-38
No files found.
a2billing/__init__.py
0 → 100644
View file @
be2d2b5b
a2billing/a2billing.py
0 → 100644
View file @
be2d2b5b
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
cli.py
View file @
be2d2b5b
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 A
ctualizar.
list[str]: Listado de
números que podemos a
ctualizar.
"""
"""
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
=
'
\n
Actualizació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\n
Sincronizació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__"
:
...
...
mbilling/functions.py
View file @
be2d2b5b
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
]
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment