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.
179 lines
6.9 KiB
179 lines
6.9 KiB
package NGCP::Panel::Utils::Voucher;
|
|
use Sipwise::Base;
|
|
use Crypt::Rijndael;
|
|
use MIME::Base64;
|
|
use NGCP::Panel::Utils::DateTime;
|
|
|
|
sub encrypt_code {
|
|
my ($c, $plain) = @_;
|
|
|
|
my $key = $c->config->{vouchers}->{key};
|
|
my $iv = $c->config->{vouchers}->{iv};
|
|
|
|
# pkcs#5 padding to 16 bytes blocksize
|
|
my $pad = 16 - (length $plain) % 16;
|
|
$plain .= pack('C', $pad) x $pad;
|
|
|
|
my $cipher = Crypt::Rijndael->new(
|
|
$key,
|
|
Crypt::Rijndael::MODE_CBC()
|
|
);
|
|
$cipher->set_iv($iv);
|
|
my $encrypted = $cipher->encrypt($plain);
|
|
my $b64 = encode_base64($encrypted, '');
|
|
return $b64;
|
|
}
|
|
|
|
sub decrypt_code {
|
|
my ($c, $code) = @_;
|
|
|
|
my $key = $c->config->{vouchers}->{key};
|
|
my $iv = $c->config->{vouchers}->{iv};
|
|
|
|
my $cipher = Crypt::Rijndael->new(
|
|
$key,
|
|
Crypt::Rijndael::MODE_CBC()
|
|
);
|
|
$cipher->set_iv($iv);
|
|
my $encrypted = decode_base64($code);
|
|
my $plain = $cipher->decrypt($encrypted) . "";
|
|
# remove padding
|
|
$plain =~ s/[\x01-\x1e]*$//;
|
|
return $plain;
|
|
}
|
|
|
|
sub check_topup {
|
|
my %params = @_;
|
|
my ($c,$plain_code,$voucher_id,$now,$subscriber_id,$contract,$package_id,$schema,$err_code,$entities,$resource) = @params{qw/c plain_code voucher_id now subscriber_id contract package_id schema err_code entities resource/};
|
|
|
|
$schema //= $c->model('DB');
|
|
$now //= NGCP::Panel::Utils::DateTime::current_local;
|
|
|
|
if (!defined $err_code || ref $err_code ne 'CODE') {
|
|
$err_code = sub { return 0; };
|
|
}
|
|
|
|
my $reseller_id;
|
|
if($c->user->roles eq "admin") {
|
|
} elsif($c->user->roles eq "reseller") {
|
|
$reseller_id = $c->user->reseller_id;
|
|
}
|
|
|
|
if (defined $subscriber_id) {
|
|
my $subscriber = $schema->resultset('voip_subscribers')->find($subscriber_id);
|
|
unless($subscriber) {
|
|
if (defined $resource) {
|
|
$resource->{subscriber_id} = undef if exists $resource->{subscriber_id};
|
|
$resource->{subscriber}->{id} = undef if (exists $resource->{subscriber} && exists $resource->{subscriber}->{id});
|
|
}
|
|
return 0 unless &{$err_code}("Unknown subscriber ID $subscriber_id.");
|
|
}
|
|
$entities->{subscriber} = $subscriber if defined $entities;
|
|
$contract //= $subscriber->contract;
|
|
}
|
|
|
|
$entities->{contract} = $contract if defined $entities;
|
|
|
|
unless($contract->status eq 'active') {
|
|
return 0 unless &{$err_code}('Customer contract is not active.');
|
|
}
|
|
unless($contract->contact->reseller) {
|
|
return 0 unless &{$err_code}('Contract is not a customer contract.');
|
|
}
|
|
|
|
# if reseller, check if subscriber_id belongs to the calling reseller
|
|
if($reseller_id && $reseller_id != $contract->contact->reseller_id) {
|
|
return 0 unless &{$err_code}('Subscriber customer contract belongs to another reseller.');
|
|
}
|
|
|
|
if (defined $plain_code || defined $voucher_id) {
|
|
|
|
my $voucher;
|
|
my $dtf = $schema->storage->datetime_parser;
|
|
|
|
if (defined $plain_code) {
|
|
$voucher = $schema->resultset('vouchers')->search_rs({
|
|
code => encrypt_code($c, $plain_code),
|
|
used_at => { '=' => \"'0000-00-00 00:00:00'" } , #used_by_subscriber_id => undef,
|
|
valid_until => { '>=' => $dtf->format_datetime($now) },
|
|
reseller_id => $contract->contact->reseller_id,
|
|
},{
|
|
for => 'update',
|
|
})->first;
|
|
unless($voucher) {
|
|
if (defined $resource) {
|
|
$resource->{voucher_id} = undef if exists $resource->{voucher_id};
|
|
$resource->{voucher}->{id} = undef if (exists $resource->{voucher} && exists $resource->{voucher}->{id});
|
|
}
|
|
return 0 unless &{$err_code}("Invalid voucher code '$plain_code', already used or expired.");
|
|
}
|
|
} else {
|
|
$voucher = $schema->resultset('vouchers')->search_rs({
|
|
id => $voucher_id,
|
|
used_at => { '=' => \"'0000-00-00 00:00:00'" }, #used_by_subscriber_id => undef,
|
|
valid_until => { '>=' => $dtf->format_datetime($now) },
|
|
reseller_id => $contract->contact->reseller_id,
|
|
},{
|
|
for => 'update',
|
|
})->first;
|
|
unless($voucher) {
|
|
if (defined $resource) {
|
|
$resource->{voucher_id} = undef if exists $resource->{voucher_id};
|
|
$resource->{voucher}->{id} = undef if (exists $resource->{voucher} && exists $resource->{voucher}->{id});
|
|
}
|
|
return 0 unless &{$err_code}("Invalid voucher ID $voucher_id, already used or expired.");
|
|
}
|
|
}
|
|
|
|
$entities->{voucher} = $voucher if defined $entities;
|
|
|
|
if($voucher->customer_id && $contract->id != $voucher->customer_id) {
|
|
return 0 unless &{$err_code}('Voucher is reserved for a different customer.');
|
|
}
|
|
unless($voucher->reseller_id == $contract->contact->reseller_id) {
|
|
return 0 unless &{$err_code}('Voucher belongs to another reseller.');
|
|
}
|
|
|
|
} else {
|
|
my $package = undef;
|
|
if (defined $package_id) {
|
|
$package = $schema->resultset('profile_packages')->find($package_id);
|
|
unless($package) {
|
|
if (defined $resource) {
|
|
$resource->{package_id} = undef if exists $resource->{package_id};
|
|
$resource->{package}->{id} = undef if (exists $resource->{package} && exists $resource->{package}->{id});
|
|
}
|
|
return 0 unless &{$err_code}("Unknown profile package ID $package_id.");
|
|
}
|
|
$entities->{package} = $package if defined $entities;
|
|
if ($package->reseller_id && $package->reseller_id != $contract->contact->reseller_id) {
|
|
return 0 unless &{$err_code}('Profile package belongs to another reseller.');
|
|
}
|
|
}
|
|
}
|
|
|
|
# TODO: add and check billing.vouchers.active flag for internal/emergency use
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
sub get_datatable_cols {
|
|
|
|
my ($c,$hide_package) = @_;
|
|
return (
|
|
{ name => "id", "search" => 1, "title" => $c->loc("#") },
|
|
$c->user->billing_data ? { name => "code", "search" => 1, "title" => $c->loc("Code") } : (),
|
|
{ name => "amount", "search" => 1, "title" => $c->loc("Amount") },
|
|
{ name => "reseller.name", "search" => 1, "title" => $c->loc("Reseller") },
|
|
$hide_package ? () : { name => "profile_package.name", "search" => 1, "title" => $c->loc("Profile Package") },
|
|
#{ name => "customer_contact_email", "search" => 1, "title" => $c->loc("Reserved for Customer") },
|
|
{ name => "customer_id", "search" => 1, "title" => $c->loc("For Contract #") },
|
|
{ name => "valid_until", "search" => 1, "title" => $c->loc("Valid Until") },
|
|
{ name => "used_at", "search" => 1, "title" => $c->loc("Used At") },
|
|
{ name => "used_by_subscriber.id", "search" => 1, "title" => $c->loc("Used By Subscriber #") },
|
|
);
|
|
}
|
|
|
|
1;
|