mirror of
https://gitlab.com/t6353/sharee.bike.git
synced 2025-05-11 14:27:28 +02:00
Setting payment_provider to manually and disable CC
This commit is contained in:
parent
4055e5a81b
commit
d200ca3593
15 changed files with 358 additions and 31 deletions
|
@ -760,14 +760,14 @@ elsif($q->param('request') eq "stations_available"){
|
||||||
|
|
||||||
#App merchant message
|
#App merchant message
|
||||||
#if($user_agent =~ /konrad/i && $dbt->{copri_conf}->{betau_id}->{$authraw->{c_id}} && $varenv{cms}->{'App-merchant-message'}->{txt}){
|
#if($user_agent =~ /konrad/i && $dbt->{copri_conf}->{betau_id}->{$authraw->{c_id}} && $varenv{cms}->{'App-merchant-message'}->{txt}){
|
||||||
if($user_agent =~ /konrad/i && $varenv{cms}->{'App-merchant-message'}->{txt}){
|
if($user_agent =~ /sharee/i && $authraw->{int03} && $authraw->{int03} == 2 && $varenv{cms}->{'App-merchant-message'}->{txt}){
|
||||||
#if($epoch_now >= $epoch_start && $epoch_now <= $epoch_end){
|
#if($epoch_now >= $epoch_start && $epoch_now <= $epoch_end){
|
||||||
$response->{merchant_message} = $varenv{cms}->{'App-merchant-message'}->{txt};
|
$response->{merchant_message} = $varenv{cms}->{'App-merchant-message'}->{txt};
|
||||||
#}
|
#}
|
||||||
}
|
}
|
||||||
#App merchant message bayern
|
#App merchant message bayern
|
||||||
#if($user_agent =~ /bayern/i && $varenv{cms}->{'App-merchant-message-bayern'}->{txt}){
|
#if($user_agent =~ /bayern/i && $user_agent_subversion <= 380 && $varenv{cms}->{'App-merchant-message-bayern'}->{txt}){
|
||||||
if($user_agent =~ /bayern/i && $user_agent_subversion <= 380 && $varenv{cms}->{'App-merchant-message-bayern'}->{txt}){
|
if($user_agent =~ /bayern|konrad/i && $varenv{cms}->{'App-merchant-message-bayern'}->{txt}){
|
||||||
#if($epoch_now >= $epoch_start && $epoch_now <= $epoch_end){
|
#if($epoch_now >= $epoch_start && $epoch_now <= $epoch_end){
|
||||||
$response->{merchant_message} = $varenv{cms}->{'App-merchant-message-bayern'}->{txt};
|
$response->{merchant_message} = $varenv{cms}->{'App-merchant-message-bayern'}->{txt};
|
||||||
#}
|
#}
|
||||||
|
|
|
@ -122,19 +122,21 @@ sub battery_percent {
|
||||||
}
|
}
|
||||||
|
|
||||||
#payable_check and rentable_check
|
#payable_check and rentable_check
|
||||||
|
#Disabled adr.int03==2 alias CC, 2025-02-13
|
||||||
#int03==1 if SEPA, 2 if CC, 3 if Prepaid
|
#int03==1 if SEPA, 2 if CC, 3 if Prepaid
|
||||||
#int04==1 if emailAck
|
#int04==1 if emailAck
|
||||||
#int13==1 if smsAck
|
#int13==1 if smsAck
|
||||||
#int12==1|2|3|4 than Vde
|
#int12==1|2|3|4 than Vde
|
||||||
#int14==1 if AGB
|
#int14==1 if AGB
|
||||||
#int18>=1 if payAck (must be only set on SEPA and CC)
|
#int18>=1 if payment_provider=payone payAck (must be only set on SEPA and CC)
|
||||||
sub isuser_rentable {
|
sub isuser_rentable {
|
||||||
my $self = shift;
|
my $self = shift;
|
||||||
my $auth = shift;
|
my $auth = shift;
|
||||||
my $varenv = shift || "";
|
my $varenv = shift || "";
|
||||||
|
|
||||||
my $rentable_check=0;
|
my $rentable_check=0;
|
||||||
if($auth->{int03} && $auth->{ct_name} && ($auth->{int18} && (($auth->{int03} == 1 && $auth->{ct_name} =~ /^\w{2}-\w+/) || ($auth->{int03} == 2 && length($auth->{ct_name}) >= 19))) || ($auth->{int03} == 3 && $auth->{ct_name} =~ /Prepaid-\d+/i)){
|
|
||||||
|
#if($auth->{int03} && $auth->{ct_name} && ($auth->{int18} && (($auth->{int03} == 1 && $auth->{ct_name} =~ /^\w{2}-\w+/) || ($auth->{int03} == 2 && length($auth->{ct_name}) >= 19))) || ($auth->{int03} == 3 && $auth->{ct_name} =~ /Prepaid-\d+/i)){
|
||||||
|
if($auth->{int03} && $auth->{ct_name} && ($auth->{int03} == 1 && $auth->{ct_name} =~ /^\w{2}-\w+/) || ($auth->{int03} == 3 && $auth->{ct_name} =~ /Prepaid-\d+/i)){
|
||||||
$rentable_check=1;#Account is payable
|
$rentable_check=1;#Account is payable
|
||||||
if(!$auth->{int12} && $auth->{txt08} && $auth->{int04} == 1 && $auth->{int13} == 1 && $auth->{int14}){
|
if(!$auth->{int12} && $auth->{txt08} && $auth->{int04} == 1 && $auth->{int13} == 1 && $auth->{int14}){
|
||||||
$rentable_check=2;#Account is rentalable, with all Ack's and Vde=0
|
$rentable_check=2;#Account is rentalable, with all Ack's and Vde=0
|
||||||
|
|
|
@ -179,7 +179,7 @@ sub update_operatorsloop {
|
||||||
|
|
||||||
}
|
}
|
||||||
}elsif($todo eq "delete"){
|
}elsif($todo eq "delete"){
|
||||||
$bw->log("DELETE adr from operators and at last primary $sharee_operator",$record_primary,"");
|
$bw->log("DELETE adr from operators and at last primary $sharee_operator",$record_primary->{c_id},"");
|
||||||
$rows += $self->delete_content($dbh_operator,"contentadr",$record_primary->{c_id});
|
$rows += $self->delete_content($dbh_operator,"contentadr",$record_primary->{c_id});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
247
copri4/main/src/Mod/IBAN.pm
Normal file
247
copri4/main/src/Mod/IBAN.pm
Normal file
|
@ -0,0 +1,247 @@
|
||||||
|
package IBAN;
|
||||||
|
|
||||||
|
require 5.005_62;
|
||||||
|
use Math::BigInt;
|
||||||
|
use strict;
|
||||||
|
use vars qw($VERSION @errors);
|
||||||
|
|
||||||
|
$VERSION = '0.06';
|
||||||
|
|
||||||
|
# error codes
|
||||||
|
use constant IBAN_CTR => 0;
|
||||||
|
use constant IBAN_BBAN => 1;
|
||||||
|
use constant IBAN_ISO => 2;
|
||||||
|
use constant IBAN_FORMAT => 3;
|
||||||
|
use constant IBAN_FORMAT2 => 4;
|
||||||
|
use constant IBAN_INVALID => 5;
|
||||||
|
|
||||||
|
sub new {
|
||||||
|
my ($class) = @_;
|
||||||
|
my $self = {};
|
||||||
|
bless $self, $class;
|
||||||
|
return $self;
|
||||||
|
} ## end sub new
|
||||||
|
# --------------------------------------
|
||||||
|
sub getIBAN {
|
||||||
|
my ($self, $args) = @_;
|
||||||
|
my $iso = uc $args->{ISO};
|
||||||
|
my $bban = $args->{BBAN};
|
||||||
|
my $bic = $args->{BIC};
|
||||||
|
my $ac = $args->{AC};
|
||||||
|
delete $self->{ERRORS};
|
||||||
|
push @{$self->{ERRORS}}, IBAN_CTR unless $iso ;
|
||||||
|
push @{$self->{ERRORS}}, IBAN_BBAN unless $bban || ($bic && $ac);
|
||||||
|
return if $self->{ERRORS};
|
||||||
|
$iso =~ tr/A-Za-z//cd if $iso;
|
||||||
|
$bban =~ tr/A-Za-z09//cd if $bban;
|
||||||
|
$ac =~ tr/A-Za-z09//cd if $ac;
|
||||||
|
|
||||||
|
return unless $iso;
|
||||||
|
$iso = uc $iso;
|
||||||
|
$args->{CV} = $iso;
|
||||||
|
$args->{CV} =~ s/([A-Z])/(ord $1)-55/eg;
|
||||||
|
my $no;
|
||||||
|
$args->{ISO} = $iso;
|
||||||
|
for ($iso) {
|
||||||
|
m/^DE$/ and $no = $self->iban_de($args), last;
|
||||||
|
$no = $self->iban_unspec($args);
|
||||||
|
}
|
||||||
|
return $no;
|
||||||
|
}
|
||||||
|
# --------------------------------------
|
||||||
|
sub iban_de {
|
||||||
|
my $self = shift;
|
||||||
|
my $args = shift;
|
||||||
|
$args->{BBAN} ||= sprintf "%08s%010s", $args->{BIC},$args->{AC};
|
||||||
|
my $no = sprintf "%018s%4s00", $args->{BBAN}, $args->{CV};
|
||||||
|
my $tmp = $no % 97;
|
||||||
|
my $bigint = Math::BigInt->new($no);
|
||||||
|
my $mod = sprintf "%2d", 98 - ($bigint % 97);
|
||||||
|
substr($no,-6,6) = "";
|
||||||
|
$no = 'IBAN '.$args->{ISO}.$mod.$no;
|
||||||
|
return $no;
|
||||||
|
}
|
||||||
|
# --------------------------------------
|
||||||
|
sub iban_unspec {
|
||||||
|
my $self = shift;
|
||||||
|
my $args = shift;
|
||||||
|
push @{$self->{ERRORS}}, IBAN_BBAN unless $args->{BBAN};
|
||||||
|
return if $self->{ERRORS};
|
||||||
|
my $no = sprintf "%s%4s00", $args->{BBAN}, $args->{CV};
|
||||||
|
my $bigint = Math::BigInt->new($no);
|
||||||
|
my $mod = 98 - ($bigint % 97);
|
||||||
|
substr($no,-6,6) = "";
|
||||||
|
$no = 'IBAN '.$args->{ISO}.$mod.$no;
|
||||||
|
return $no;
|
||||||
|
}
|
||||||
|
# --------------------------------------
|
||||||
|
sub getError {
|
||||||
|
return unless $_[0]->{ERRORS};
|
||||||
|
return @{$_[0]->{ERRORS}};
|
||||||
|
}
|
||||||
|
# --------------------------------------
|
||||||
|
sub printError {
|
||||||
|
return unless $_[0]->{ERRORS};
|
||||||
|
print "$errors[$_]\n" for @{$_[0]->{ERRORS}};
|
||||||
|
}
|
||||||
|
# --------------------------------------
|
||||||
|
sub country {
|
||||||
|
return $_[0]->{COUNTRY};
|
||||||
|
}
|
||||||
|
# --------------------------------------
|
||||||
|
sub valid {
|
||||||
|
my ($self, $ib) = @_;
|
||||||
|
delete $self->{ERRORS};
|
||||||
|
# remove spaces
|
||||||
|
$ib =~ tr/ //d;
|
||||||
|
# invalid characters
|
||||||
|
#(push @{$self->{ERRORS}}, IBAN_FORMAT2), return if $ib =~ tr/A-Za-z0-9//c;
|
||||||
|
$ib =~ s/^IBAN//i;
|
||||||
|
push @{$self->{ERRORS}}, IBAN_FORMAT unless $ib =~ m/^[A-Z][A-Z]/i;
|
||||||
|
return if $self->{ERRORS};
|
||||||
|
my $iso = substr $ib, 0, 2, "";
|
||||||
|
$iso =~ s/([A-Z])/(ord $1)-55/eg;
|
||||||
|
my $check = substr $ib, 0, 2, "";
|
||||||
|
# convert alpha characters to their ascii code
|
||||||
|
$ib =~ s/([A-Z])/(ord $1)-55/eg;
|
||||||
|
# iban still contains characters which are not numbers!
|
||||||
|
(push @{$self->{ERRORS}}, IBAN_FORMAT2), return if $ib =~ tr/0-9//c;
|
||||||
|
$ib .= "$iso$check";
|
||||||
|
$ib = Math::BigInt->new($ib);
|
||||||
|
push @{$self->{ERRORS}}, IBAN_INVALID and return unless ($ib % 97)==1;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
# --------------------------------------
|
||||||
|
|
||||||
|
@errors = (
|
||||||
|
"No Country or Iso-Code supplied",
|
||||||
|
"No BBAN (Bank-Number) or Bank Identifier and Accountnumber supplied",
|
||||||
|
"Could not find country",
|
||||||
|
"IBAN must contain two-letter ISO-Code at the beginning",
|
||||||
|
"IBAN must only contain only alphanumerics after the ISO-code",
|
||||||
|
"IBAN is invalid",
|
||||||
|
);
|
||||||
|
|
||||||
|
1;
|
||||||
|
__END__
|
||||||
|
|
||||||
|
=head1 NAME
|
||||||
|
|
||||||
|
Business::IBAN - Validate and generate IBANs
|
||||||
|
|
||||||
|
=head1 SYNOPSIS
|
||||||
|
|
||||||
|
use Business::IBAN;
|
||||||
|
use Locale::Country;
|
||||||
|
my $cc = country2code('Germany');
|
||||||
|
my $iban = Business::IBAN->new();
|
||||||
|
|
||||||
|
# ---------- generate
|
||||||
|
my $ib = $iban->getIBAN(
|
||||||
|
{
|
||||||
|
ISO => $cc, # or "DE", etc.
|
||||||
|
BIC => 12345678, # Bank Identifier Code, meaning the BLZ
|
||||||
|
# in Germany
|
||||||
|
AC => "1234567890",
|
||||||
|
});
|
||||||
|
# or
|
||||||
|
my $ib = $iban->getIBAN(
|
||||||
|
{
|
||||||
|
ISO => "DE",
|
||||||
|
BBAN => 123456781234567890,
|
||||||
|
});
|
||||||
|
if ($ib) {
|
||||||
|
print "IBAN is $ib\n";
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$iban->printError();
|
||||||
|
# or
|
||||||
|
my @errors = $iban->getError();
|
||||||
|
# print your own error messages (for description of error-
|
||||||
|
# codes see section ERROR-CODES
|
||||||
|
}
|
||||||
|
|
||||||
|
# ------------ validate
|
||||||
|
if ($iban->valid($ib)) {
|
||||||
|
# note: this also accepts IBANs in paper format with spaces added
|
||||||
|
print "$ib is valid\n";
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$iban->printError();
|
||||||
|
}
|
||||||
|
|
||||||
|
=head1 DESCRIPTION
|
||||||
|
|
||||||
|
With this module you can validate IBANs (International Bank
|
||||||
|
Account Number) like "IBAN DE97123456781234567890" (ISO 13616).
|
||||||
|
(Note: spaces between numbers are allowed.)
|
||||||
|
Note that this dos not (and cannot) assure that the bank
|
||||||
|
account exists or that the bank account number for the
|
||||||
|
bank itself is valid.
|
||||||
|
You can also create an IBAN if you supply
|
||||||
|
|
||||||
|
=over 4
|
||||||
|
|
||||||
|
=item
|
||||||
|
|
||||||
|
- your BBAN (Basic Bank Account Number),
|
||||||
|
(or for germany your BLZ and account
|
||||||
|
number are sufficient),
|
||||||
|
|
||||||
|
=item
|
||||||
|
|
||||||
|
- and either your country code (ISO3166)
|
||||||
|
or the english name for your country.
|
||||||
|
|
||||||
|
But note that only your bank is supposed to create your official IBAN.
|
||||||
|
|
||||||
|
=back
|
||||||
|
|
||||||
|
=head2 REQUIRES
|
||||||
|
|
||||||
|
To get your country code the module Locale::Country is required, which
|
||||||
|
you can get from www.cpan.org. It's a standard module since perl-version
|
||||||
|
5.7.2. If you know your country code, you don't need the module.
|
||||||
|
|
||||||
|
=head2 EXPORT
|
||||||
|
|
||||||
|
None by default. All methods are accessed over the object.
|
||||||
|
|
||||||
|
|
||||||
|
=head2 ERROR-CODES
|
||||||
|
|
||||||
|
You can print your own error-messages. The array you get from
|
||||||
|
my @errors = $iban->getError();
|
||||||
|
are numbers which stand for the following errors:
|
||||||
|
|
||||||
|
0: No Country or Iso-Code supplied
|
||||||
|
1: No BBAN (Bank-Number) or Bank Identifier and Accountnumber supplied
|
||||||
|
2: Could not find country
|
||||||
|
3: IBAN must contain two-letter ISO-Code at the beginning
|
||||||
|
4: IBAN must only contain only alphanumerics after the ISO-code
|
||||||
|
5: IBAN is invalid
|
||||||
|
|
||||||
|
=head2 CAVEATS
|
||||||
|
|
||||||
|
Please note that this program is intended to validate IBANs and generate
|
||||||
|
them for you if you have your BBAN. It's not for generating valid
|
||||||
|
numbers for illegal purposes. The algorithm is simple and publicly
|
||||||
|
available for everyone. You can find informations about the IBAN at
|
||||||
|
|
||||||
|
=over 4
|
||||||
|
|
||||||
|
=item http://www.ecbs.org
|
||||||
|
|
||||||
|
=item http://www.iban.ch
|
||||||
|
|
||||||
|
=back
|
||||||
|
|
||||||
|
=head1 VERSION
|
||||||
|
|
||||||
|
Business::IBAN Version 0.06
|
||||||
|
|
||||||
|
=head1 AUTHOR
|
||||||
|
|
||||||
|
Tina Mueller. tinita(at)cpan.org
|
||||||
|
|
||||||
|
=cut
|
|
@ -726,7 +726,7 @@ sub handler {
|
||||||
exit 0;
|
exit 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
elsif(!$users_sharee->{c_id} && !$R::logedout && ($path !~ /$varenv{mandant}\/Karte|$varenv{mandant}\/Anmelden|$varenv{mandant}\/Account|$varenv{mandant}\/Kontakt/)){
|
elsif(!$users_sharee->{c_id} && !$R::logedout && ($path !~ /$varenv{mandant}\/Karte|$varenv{mandant}\/Anmelden|$varenv{mandant}\/Account|$varenv{mandant}\/Kontakt|PDFGenerator/)){
|
||||||
print redirect("$varenv{wwwhost}?logedout=1$session_and");
|
print redirect("$varenv{wwwhost}?logedout=1$session_and");
|
||||||
exit 0;
|
exit 0;
|
||||||
}
|
}
|
||||||
|
@ -809,6 +809,7 @@ sub handler {
|
||||||
#my $jquery = "$varenv{metahost}/$dbt->{copri_conf}->{jsscript}";
|
#my $jquery = "$varenv{metahost}/$dbt->{copri_conf}->{jsscript}";
|
||||||
my $jquery = "$varenv{metahost}/$dbt->{shareeapp_conf}->{jquery}";#used by CalReserv / rentalator.js
|
my $jquery = "$varenv{metahost}/$dbt->{shareeapp_conf}->{jquery}";#used by CalReserv / rentalator.js
|
||||||
my $jquery_ui = "$varenv{metahost}/$dbt->{copri_conf}->{jsscript}";
|
my $jquery_ui = "$varenv{metahost}/$dbt->{copri_conf}->{jsscript}";
|
||||||
|
|
||||||
my $style_jquery_ui = "";
|
my $style_jquery_ui = "";
|
||||||
my $js_bootstrap = "$varenv{metahost}/$dbt->{shareeapp_conf}->{js_bootstrap}";
|
my $js_bootstrap = "$varenv{metahost}/$dbt->{shareeapp_conf}->{js_bootstrap}";
|
||||||
my $style_bootstrap = "$varenv{metahost}/$dbt->{shareeapp_conf}->{style_bootstrap}";
|
my $style_bootstrap = "$varenv{metahost}/$dbt->{shareeapp_conf}->{style_bootstrap}";
|
||||||
|
|
|
@ -173,6 +173,12 @@ sub book_payment {
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
#SEPA manually
|
||||||
|
elsif($update_ctt->{int04} == 10){
|
||||||
|
$update_ctt->{int14} = "null";
|
||||||
|
$update_ctt->{pay_time} = "now()";
|
||||||
|
$feedb->{u_rows} = $dbt->update_record($dbh,$update_ctt,$ctt);
|
||||||
|
}
|
||||||
#Storno or Zahlungsausfall
|
#Storno or Zahlungsausfall
|
||||||
elsif($ctt->{txt00} eq "Storno" || $update_ctt->{int04} == 7){
|
elsif($ctt->{txt00} eq "Storno" || $update_ctt->{int04} == 7){
|
||||||
$update_ctt->{int14} = "null";
|
$update_ctt->{int14} = "null";
|
||||||
|
@ -1073,10 +1079,16 @@ sub payone_capture {
|
||||||
#set also state because we still need (payone) for some text selection TODO
|
#set also state because we still need (payone) for some text selection TODO
|
||||||
my $state = $ctt->{state} || "";
|
my $state = $ctt->{state} || "";
|
||||||
my $p_hash = $dbt->{shareedms_conf}->{payment_state2};
|
my $p_hash = $dbt->{shareedms_conf}->{payment_state2};
|
||||||
if($ctadr->{ct_name} =~ /^\w{2}-\d+/){
|
#SEPA payone
|
||||||
|
if($ctadr->{ct_name} =~ /(PO|TM)-\d+/){
|
||||||
$state = $p_hash->{1};
|
$state = $p_hash->{1};
|
||||||
$update_ctt->{int04} = 1;
|
$update_ctt->{int04} = 1;
|
||||||
}
|
}
|
||||||
|
#SEPA manually
|
||||||
|
if($ctadr->{ct_name} =~ /MA-\d+/){
|
||||||
|
$state = $p_hash->{10};
|
||||||
|
$update_ctt->{int04} = 10;
|
||||||
|
}
|
||||||
if(length($ctadr->{ct_name}) >= 19){
|
if(length($ctadr->{ct_name}) >= 19){
|
||||||
$state = $p_hash->{2};
|
$state = $p_hash->{2};
|
||||||
$update_ctt->{int04} = 2;
|
$update_ctt->{int04} = 2;
|
||||||
|
|
|
@ -581,7 +581,7 @@ td {
|
||||||
if($key =~ /txt5\d/){
|
if($key =~ /txt5\d/){
|
||||||
$ctf->{$key} = $q->unescapeHTML("$ctf->{$key}");
|
$ctf->{$key} = $q->unescapeHTML("$ctf->{$key}");
|
||||||
$ctf->{$key} = $lb->newline($ctf->{$key},"","");
|
$ctf->{$key} = $lb->newline($ctf->{$key},"","");
|
||||||
$ctt->{state} =~ s/\(payone.*//;
|
$ctt->{state} =~ s/\(.*//;#delete like (payone)
|
||||||
if($des =~ /$ctt->{state}/){
|
if($des =~ /$ctt->{state}/){
|
||||||
if($sum_brutto < 0){
|
if($sum_brutto < 0){
|
||||||
$payment_text = "$ctf->{txt58}";
|
$payment_text = "$ctf->{txt58}";
|
||||||
|
@ -835,7 +835,7 @@ td {
|
||||||
if($key =~ /txt5\d/){
|
if($key =~ /txt5\d/){
|
||||||
$ctf->{$key} = $q->unescapeHTML("$ctf->{$key}");
|
$ctf->{$key} = $q->unescapeHTML("$ctf->{$key}");
|
||||||
$ctf->{$key} = $lb->newline($ctf->{$key},"","");
|
$ctf->{$key} = $lb->newline($ctf->{$key},"","");
|
||||||
$ctt->{state} =~ s/\(payone.*//;
|
$ctt->{state} =~ s/\(.*//;
|
||||||
if($des =~ /$ctt->{state}/ && ($j <= $max_table_wc || $break_table_wc)){
|
if($des =~ /$ctt->{state}/ && ($j <= $max_table_wc || $break_table_wc)){
|
||||||
if($sum_parts19 < 0){
|
if($sum_parts19 < 0){
|
||||||
$payment_text = "$ctf->{txt58}";
|
$payment_text = "$ctf->{txt58}";
|
||||||
|
|
|
@ -26,6 +26,7 @@ use Mod::Basework;
|
||||||
use Mod::Payment;
|
use Mod::Payment;
|
||||||
#use Mod::MailTransport;
|
#use Mod::MailTransport;
|
||||||
use Mod::SMSTransport;
|
use Mod::SMSTransport;
|
||||||
|
use Mod::IBAN;#if no payment_provider defined
|
||||||
use Data::Dumper;
|
use Data::Dumper;
|
||||||
|
|
||||||
my $cf = new Config;
|
my $cf = new Config;
|
||||||
|
@ -34,9 +35,10 @@ my $lb = new Libenz;
|
||||||
my $dbt = new DBtank;
|
my $dbt = new DBtank;
|
||||||
my $apif = new APIfunc;
|
my $apif = new APIfunc;
|
||||||
my $bw = new Basework;
|
my $bw = new Basework;
|
||||||
my $payone = new Payment;
|
my $pay = new Payment;
|
||||||
#my $mailtrans = new MailTransport;
|
#my $mailtrans = new MailTransport;
|
||||||
my $smstrans = new SMSTransport;
|
my $smstrans = new SMSTransport;
|
||||||
|
my $ibanmod = IBAN->new();
|
||||||
|
|
||||||
my $q = new CGI;
|
my $q = new CGI;
|
||||||
my $uri_encode = URI::Encode->new( { encode_reserved => 1 } );
|
my $uri_encode = URI::Encode->new( { encode_reserved => 1 } );
|
||||||
|
@ -539,8 +541,10 @@ sub save_account(){
|
||||||
|
|
||||||
my $iban = $ctadr->{txt22} || "";
|
my $iban = $ctadr->{txt22} || "";
|
||||||
$iban =~ s/\s//g;
|
$iban =~ s/\s//g;
|
||||||
|
$iban = uc($iban);
|
||||||
my $iban_reject = 0;
|
my $iban_reject = 0;
|
||||||
$iban_reject = 1 if($iban =~ /DE33700202700000091600/i);#fraud
|
$iban_reject = 1 if($iban =~ /DE33700202xxxxxxxxxx/i);#fraud
|
||||||
|
|
||||||
if($R::request eq "managemandate" && $ctadr->{int03} == 1 && !$iban_reject){
|
if($R::request eq "managemandate" && $ctadr->{int03} == 1 && !$iban_reject){
|
||||||
|
|
||||||
my $vde_on_fail = $ctadr->{int12} || 3;#keep last or set 3
|
my $vde_on_fail = $ctadr->{int12} || 3;#keep last or set 3
|
||||||
|
@ -561,17 +565,40 @@ sub save_account(){
|
||||||
$ret_conflict = "failure::conflict_txt22\&txt22=$encoded_val#top";
|
$ret_conflict = "failure::conflict_txt22\&txt22=$encoded_val#top";
|
||||||
}else{
|
}else{
|
||||||
|
|
||||||
my $payone_mival = $payone->managemandate_main(\%varenv,$ctadr,"",$owner);
|
#depends on payment_provider
|
||||||
if($payone_mival && $payone_mival =~ /\w{2}-\w+/){
|
if($dbt->{primary}->{payment_provider} eq "payone"){
|
||||||
|
my $pay_mival = $pay->managemandate_main(\%varenv,$ctadr,"",$owner);
|
||||||
|
if($pay_mival && $pay_mival =~ /\w{2}-\w+/){
|
||||||
|
|
||||||
#payment_ack payAck
|
#payment_ack payAck
|
||||||
system("$dbt->{copri_conf}->{basedir}/$varenv{syshost}/src/scripts/payment_ack.pl '$varenv{syshost}' 'payment_ackSEPA' '$ctadr->{c_id}' '$owner' &");
|
system("$dbt->{copri_conf}->{basedir}/$varenv{syshost}/src/scripts/payment_ack.pl '$varenv{syshost}' 'payment_ackSEPA' '$ctadr->{c_id}' '$owner' &");
|
||||||
|
|
||||||
$vde_on_fail = 0 if($vde_on_fail != 2);
|
$vde_on_fail = 0 if($vde_on_fail != 2);
|
||||||
$u_rows = $dbt->update_one($dbh,$update_adr,"int12=$vde_on_fail");#Vde
|
$u_rows = $dbt->update_one($dbh,$update_adr,"int12=$vde_on_fail");#Vde
|
||||||
}else{
|
}else{
|
||||||
$u_rows = $dbt->update_one($dbh,$update_adr,"int12=$vde_on_fail");#Vde
|
$u_rows = $dbt->update_one($dbh,$update_adr,"int12=$vde_on_fail");#Vde
|
||||||
$ret = "failure::txt22#top";
|
$ret = "failure::txt22#top";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#elsif($dbt->{primary}->{payment_provider} eq "manually"){
|
||||||
|
else{
|
||||||
|
my $valid = $ibanmod->valid($iban);
|
||||||
|
if ($valid) {
|
||||||
|
print FILE "c_id:$c_id --> IBAN:$iban --> valid:$valid\n" if($debug);
|
||||||
|
$vde_on_fail = 0 if($vde_on_fail != 2);
|
||||||
|
$u_rows = $dbt->update_one($dbh,$update_adr,"ct_name='MA-$c_id'");#MA for manually mandat
|
||||||
|
$u_rows = $dbt->update_one($dbh,$update_adr,"txt27='active'");
|
||||||
|
$u_rows = $dbt->update_one($dbh,$update_adr,"int12=$vde_on_fail");#Vde
|
||||||
|
my $ret = $pay->pdfmandat(\%varenv,$ctadr->{c_id});
|
||||||
|
print FILE "pdfmandat call generates: $ret\n" if($debug);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
my $ibanerror = $ibanmod->getError;
|
||||||
|
print FILE "c_id:$c_id --> IBAN:$iban --> ibanerror:$ibanerror\n" if($debug);
|
||||||
|
$u_rows = $dbt->update_one($dbh,$update_adr,"int12=$vde_on_fail");#Vde
|
||||||
|
$ret = "failure::txt22#top";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -354,7 +354,7 @@ EOF
|
||||||
$pay_sequence = " | sequencenr: $ctt->{int18}" if($ctt->{int18});
|
$pay_sequence = " | sequencenr: $ctt->{int18}" if($ctt->{int18});
|
||||||
|
|
||||||
my $kind_of_payment = "fehlt";
|
my $kind_of_payment = "fehlt";
|
||||||
my $p_hash = $dbt->{shareedms_conf}->{payment_state2};
|
my $p_hash = $dbt->{copri_conf}->{payment_type};
|
||||||
foreach my $s_key (sort keys (%{ $p_hash })) {
|
foreach my $s_key (sort keys (%{ $p_hash })) {
|
||||||
if($ctadr->{int03}){
|
if($ctadr->{int03}){
|
||||||
$kind_of_payment = "Kunde " . $p_hash->{$s_key} if($ctadr->{int03} == $s_key);
|
$kind_of_payment = "Kunde " . $p_hash->{$s_key} if($ctadr->{int03} == $s_key);
|
||||||
|
|
|
@ -263,6 +263,28 @@ print "</div>\n";
|
||||||
print $q->div({-class=>"content2_legende"}, $q->img({-style=>'height:37px;', -src=>"$varenv->{metahost}/img/$icon_red"}), "Lastenrad nicht verfügbar"),"\n";
|
print $q->div({-class=>"content2_legende"}, $q->img({-style=>'height:37px;', -src=>"$varenv->{metahost}/img/$icon_red"}), "Lastenrad nicht verfügbar"),"\n";
|
||||||
#print $q->div({-class=>"content2_legende"}, " "),"\n";
|
#print $q->div({-class=>"content2_legende"}, " "),"\n";
|
||||||
|
|
||||||
|
|
||||||
|
#https://developer.android.com/develop/ui/views/layout/webapps/webview
|
||||||
|
#Bind JavaScript code to Android code
|
||||||
|
#when a user taps the button, the showAndroidToast() function uses the Android interface to call the WebAppInterface.showToast() method
|
||||||
|
if($dbt->{shareeapp_conf}->{kotlinapp}){
|
||||||
|
print<<EOF
|
||||||
|
|
||||||
|
<input type="button" value="test unlock ble" onClick="showAndroidToast('test unlocking ble ...')" />
|
||||||
|
|
||||||
|
<script type="text/javascript">
|
||||||
|
function showAndroidToast(toast) {
|
||||||
|
Android.showToast(toast);
|
||||||
|
//FIXME shortly iOS Test (not working)
|
||||||
|
//https://medium.com/\@emmanuel1997/javascript-and-swift-how-to-communicate-02f432e7e267
|
||||||
|
//window.webkit.messageHandlers.buttonOne.postMessage("Button One Action");
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
EOF
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
print "$initMap|$varenv->{dbname}|$api_return->{authcookie}|$users_sharee->{c_id}" if($users_dms->{u_id} == $dbt->{copri_conf}->{superu_id});
|
print "$initMap|$varenv->{dbname}|$api_return->{authcookie}|$users_sharee->{c_id}" if($users_dms->{u_id} == $dbt->{copri_conf}->{superu_id});
|
||||||
|
|
||||||
#print "$uri_request/GBFSout?request=stations_available&authcookie=$api_return->{authcookie}";
|
#print "$uri_request/GBFSout?request=stations_available&authcookie=$api_return->{authcookie}";
|
||||||
|
|
|
@ -675,7 +675,7 @@ EOF
|
||||||
print $q->td({-style=>"font-size:0.71em;padding:0;border:0px solid green;",-colspan=>"$tdcal",-nowrap=>"1"},"$day4month"),"\n";
|
print $q->td({-style=>"font-size:0.71em;padding:0;border:0px solid green;",-colspan=>"$tdcal",-nowrap=>"1"},"$day4month"),"\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
my $sum_saldo="0";my $sum_opos="0";my $sum_prepaid="0";my $sum_ueb="0";my $sum_success="0";my $sum_SEPApayone="0";my $sum_CCpayone="0";my $sum_ausfall="0";my $sum_gutschrift="0";my $sum_einzugfail="0";my $sum_entgelt="0";my $sum_abr="0";my $close_time="";my $payment_time="";
|
my $sum_saldo=0;my $sum_opos=0;my $sum_prepaid=0;my $sum_ueb=0;my $sum_success=0;my $sum_SEPApayone=0;my $sum_SEPAmanually=0;my $sum_CCpayone=0;my $sum_ausfall=0;my $sum_gutschrift=0;my $sum_einzugfail=0;my $sum_entgelt=0;my $sum_abr=0;my $close_time="";my $payment_time="";
|
||||||
my $nr=0;my $nx=0;
|
my $nr=0;my $nx=0;
|
||||||
|
|
||||||
#BIG LOOP loop content table
|
#BIG LOOP loop content table
|
||||||
|
@ -767,6 +767,7 @@ EOF
|
||||||
$sum_opos += $ct4rel->{$id}->{int01};
|
$sum_opos += $ct4rel->{$id}->{int01};
|
||||||
}else{
|
}else{
|
||||||
$sum_SEPApayone += $ct4rel->{$id}->{int01} if($ct4rel->{$id}->{int04} == 1);
|
$sum_SEPApayone += $ct4rel->{$id}->{int01} if($ct4rel->{$id}->{int04} == 1);
|
||||||
|
$sum_SEPAmanually += $ct4rel->{$id}->{int01} if($ct4rel->{$id}->{int04} == 10);
|
||||||
$sum_CCpayone += $ct4rel->{$id}->{int01} if($ct4rel->{$id}->{int04} == 2);
|
$sum_CCpayone += $ct4rel->{$id}->{int01} if($ct4rel->{$id}->{int04} == 2);
|
||||||
$sum_prepaid += $ct4rel->{$id}->{int01} if($ct4rel->{$id}->{int04} == 3);
|
$sum_prepaid += $ct4rel->{$id}->{int01} if($ct4rel->{$id}->{int04} == 3);
|
||||||
$sum_ueb += $ct4rel->{$id}->{int01} if($ct4rel->{$id}->{int04} == 4);
|
$sum_ueb += $ct4rel->{$id}->{int01} if($ct4rel->{$id}->{int04} == 4);
|
||||||
|
@ -1166,7 +1167,7 @@ EOF
|
||||||
|
|
||||||
|
|
||||||
if(($nr > 0) && ($v_journal || $R::close_trans) && !$R::rel_id){
|
if(($nr > 0) && ($v_journal || $R::close_trans) && !$R::rel_id){
|
||||||
my $m = $k - 4;
|
my $m = $k - 5;
|
||||||
print $q->Tr();
|
print $q->Tr();
|
||||||
print $q->td({-style=>"background-color:silver;"},""),"\n";
|
print $q->td({-style=>"background-color:silver;"},""),"\n";
|
||||||
print $q->td({-class=>'tdtxt',-style=>'text-align:center;background-color:silver;',-colspan=>"$k"},"Gesamt Umsätze");
|
print $q->td({-class=>'tdtxt',-style=>'text-align:center;background-color:silver;',-colspan=>"$k"},"Gesamt Umsätze");
|
||||||
|
@ -1214,6 +1215,14 @@ EOF
|
||||||
print $q->td({-class=>'tdint',-colspan=>"$m"},"SEPA-Lastschrift (payone) Summe");
|
print $q->td({-class=>'tdint',-colspan=>"$m"},"SEPA-Lastschrift (payone) Summe");
|
||||||
print $q->td({-class=>'tdint',-colspan=>"1",-nowrap=>"1"},"$sum_SEPApayone €");
|
print $q->td({-class=>'tdint',-colspan=>"1",-nowrap=>"1"},"$sum_SEPApayone €");
|
||||||
}
|
}
|
||||||
|
if($sum_SEPAmanually != 0){
|
||||||
|
$sum_SEPAmanually = sprintf('%.2f',$sum_SEPAmanually);
|
||||||
|
$sum_success += $sum_SEPAmanually;
|
||||||
|
print $q->Tr();
|
||||||
|
print $q->td({-style=>"background-color:silver;"},""),"\n";
|
||||||
|
print $q->td({-class=>'tdint',-colspan=>"$m"},"SEPA-Lastschrift (manuell) Summe");
|
||||||
|
print $q->td({-class=>'tdint',-colspan=>"1",-nowrap=>"1"},"$sum_SEPAmanually €");
|
||||||
|
}
|
||||||
if($sum_CCpayone != 0){
|
if($sum_CCpayone != 0){
|
||||||
$sum_CCpayone = sprintf('%.2f',$sum_CCpayone);
|
$sum_CCpayone = sprintf('%.2f',$sum_CCpayone);
|
||||||
$sum_success += $sum_CCpayone;
|
$sum_success += $sum_CCpayone;
|
||||||
|
|
|
@ -376,7 +376,8 @@ sub tpl(){
|
||||||
c_id => $ctt->{content_id},
|
c_id => $ctt->{content_id},
|
||||||
};
|
};
|
||||||
#disable Leistungszeitraum workaround for SubOp
|
#disable Leistungszeitraum workaround for SubOp
|
||||||
#UPDATE contenttrans set txt20='01.05.2024 - 31.12.2024' where c_id = 29152;
|
#UPDATE contenttrans set txt20='01.05.2024 - 31.12.2024',txt29='Oberried' where c_id = 29152;
|
||||||
|
#$dbt->update_one($dbh,$update_ctt,"txt20='01.12.2023 - 31.12.2024'");
|
||||||
$dbt->update_one($dbh,$update_ctt,"txt20='$accounting_start - $accounting_end'");
|
$dbt->update_one($dbh,$update_ctt,"txt20='$accounting_start - $accounting_end'");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -498,7 +498,7 @@ EOF
|
||||||
$ctf->{$key} = $q->unescapeHTML("$ctf->{$key}");
|
$ctf->{$key} = $q->unescapeHTML("$ctf->{$key}");
|
||||||
$ctf->{$key} = $lb->newline($ctf->{$key},"","");
|
$ctf->{$key} = $lb->newline($ctf->{$key},"","");
|
||||||
if($ctt->{state}){
|
if($ctt->{state}){
|
||||||
$ctt->{state} =~ s/\(payone.*//;
|
$ctt->{state} =~ s/\(.*//;#delete like (payone)
|
||||||
if($des =~ /$ctt->{state}/){
|
if($des =~ /$ctt->{state}/){
|
||||||
if($sum_parts19 < 0){
|
if($sum_parts19 < 0){
|
||||||
$payment_text = "$ctf->{txt58}";
|
$payment_text = "$ctf->{txt58}";
|
||||||
|
@ -562,7 +562,7 @@ EOF
|
||||||
my $setdefault_payment = "";#new
|
my $setdefault_payment = "";#new
|
||||||
my $p_hash = $dbt->{shareedms_conf}->{payment_state2};
|
my $p_hash = $dbt->{shareedms_conf}->{payment_state2};
|
||||||
foreach my $s_key (sort keys (%{ $p_hash })) {
|
foreach my $s_key (sort keys (%{ $p_hash })) {
|
||||||
if($s_key <= 7){
|
if($s_key <= 7 || $s_key >= 10){
|
||||||
push @_paymentstate, "$p_hash->{$s_key}";
|
push @_paymentstate, "$p_hash->{$s_key}";
|
||||||
push @_payment_valxx, "$s_key:($s_key) $p_hash->{$s_key}";
|
push @_payment_valxx, "$s_key:($s_key) $p_hash->{$s_key}";
|
||||||
}
|
}
|
||||||
|
@ -580,10 +580,14 @@ EOF
|
||||||
$setdefault_payment = 4;
|
$setdefault_payment = 4;
|
||||||
}
|
}
|
||||||
elsif($ctadr->{int03}){
|
elsif($ctadr->{int03}){
|
||||||
if($ctadr->{ct_name} =~ /\w{2}-\d+/){
|
if($ctadr->{ct_name} =~ /(PO|TM)-\d+/){
|
||||||
$kind_of_payment = $p_hash->{1};
|
$kind_of_payment = $p_hash->{1};
|
||||||
$setdefault_payment = 1;
|
$setdefault_payment = 1;
|
||||||
}
|
}
|
||||||
|
if($ctadr->{ct_name} =~ /MA-\d+/){
|
||||||
|
$kind_of_payment = $p_hash->{10};
|
||||||
|
$setdefault_payment = 10;
|
||||||
|
}
|
||||||
if(length($ctadr->{ct_name}) >= 19){
|
if(length($ctadr->{ct_name}) >= 19){
|
||||||
$kind_of_payment = $p_hash->{2};
|
$kind_of_payment = $p_hash->{2};
|
||||||
$setdefault_payment = 2;
|
$setdefault_payment = 2;
|
||||||
|
|
|
@ -414,9 +414,10 @@ EOF
|
||||||
$checked_creditcard = 2 if($ctadr->{$key} == 2);
|
$checked_creditcard = 2 if($ctadr->{$key} == 2);
|
||||||
$checked_prepaid = 3 if($ctadr->{$key} == 3);
|
$checked_prepaid = 3 if($ctadr->{$key} == 3);
|
||||||
if($p_id == 1){
|
if($p_id == 1){
|
||||||
print $q->div({ -class=>'radio', -style=>'padding-top:20px;' },$but->radiobox_vertical("$key","$p_id","$checked_sepa",$q->img({-id=>"pic-payment" ,-style=>'height:50px;', -title=>"$dbt->{copri_conf}->{payment_type}->{$p_id}",-src=>"$varenv->{metahost}/img/payment-incasso2.png"}))),"\n";
|
print $q->div({ -class=>'radio', -style=>'padding-top:20px;' },$but->radiobox_vertical("$key","$p_id","$checked_sepa",$q->img({-id=>"pic-payment" ,-style=>'height:50px;margin:10px 0 0 10px;', -title=>"$dbt->{copri_conf}->{payment_type}->{$p_id}",-src=>"$varenv->{metahost}/img/payment-incasso2.png"}))),"\n";
|
||||||
}elsif($p_id == 2){
|
}elsif($p_id == 2){
|
||||||
print $q->div({ -class=>'radio', -style=>'padding-top:20px;' },$but->radiobox_vertical("$key","$p_id","$checked_creditcard",$q->img({-id=>"pic-payment" ,-style=>'height:25px;', -title=>"$dbt->{copri_conf}->{payment_type}->{$p_id}",-src=>"$varenv->{metahost}/img/payment-creditcard2.png"}))),"\n";
|
#print $q->div({ -class=>'radio', -style=>'padding-top:20px;' },$but->radiobox_vertical("$key","$p_id","$checked_creditcard",$q->img({-id=>"pic-payment" ,-style=>'height:25px;', -title=>"$dbt->{copri_conf}->{payment_type}->{$p_id}",-src=>"$varenv->{metahost}/img/payment-creditcard2.png"}))),"\n";
|
||||||
|
print $q->div({ -class=>'radio', -style=>'padding-top:20px;' },"<span style='text-decoration: line-through;font-size:1.5em;'>o</span>",$q->img({-id=>"pic-payment" ,-style=>'height:25px;', -title=>"$dbt->{copri_conf}->{payment_type}->{$p_id}",-src=>"$varenv->{metahost}/img/payment-creditcard2.png"}),"<br /><span style='font-size:0.91em;'>Kreditkarte ist aktuell deaktiviert</span>"),"\n";
|
||||||
}elsif($p_id == 3){
|
}elsif($p_id == 3){
|
||||||
print $q->div({ -class=>'radio', -style=>'padding-top:25px;' },$but->radiobox_vertical("$key","$p_id","$checked_prepaid","<span style='padding-left:25px;font-size:1.2em;'>Prepaid</span>")),"\n" if($ctadr->{c_id} && $dbt->{copri_conf}->{betau_id}->{$ctadr->{c_id}});#testing by contributors
|
print $q->div({ -class=>'radio', -style=>'padding-top:25px;' },$but->radiobox_vertical("$key","$p_id","$checked_prepaid","<span style='padding-left:25px;font-size:1.2em;'>Prepaid</span>")),"\n" if($ctadr->{c_id} && $dbt->{copri_conf}->{betau_id}->{$ctadr->{c_id}});#testing by contributors
|
||||||
}
|
}
|
||||||
|
|
|
@ -59,7 +59,8 @@ sub tpl(){
|
||||||
|
|
||||||
print $q->div({-class=>'content_title3'},"$varenv->{cms}->{'iframe-bank-account'}->{txt}"),"\n";
|
print $q->div({-class=>'content_title3'},"$varenv->{cms}->{'iframe-bank-account'}->{txt}"),"\n";
|
||||||
print $q->div({-class=>'content2'}, "$varenv->{cms}->{'iframe-sepa-mandat-prolog'}->{txt}"),"\n";
|
print $q->div({-class=>'content2'}, "$varenv->{cms}->{'iframe-sepa-mandat-prolog'}->{txt}"),"\n";
|
||||||
if($ctadr->{int03} == 1 && $ctadr->{ct_name} =~ /^\w{2}-\w+/ && !$ctadr->{int18}){
|
|
||||||
|
if($dbt->{primary}->{payment_provider} eq "payone" && $ctadr->{int03} == 1 && $ctadr->{ct_name} =~ /^\w{2}-\w+/ && !$ctadr->{int18}){
|
||||||
print $q->div({-class=>'content2',-style=>"color:$red"}, "$varenv->{cms}->{'iframe-payAck-failure'}->{txt}"),"\n";
|
print $q->div({-class=>'content2',-style=>"color:$red"}, "$varenv->{cms}->{'iframe-payAck-failure'}->{txt}"),"\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -108,7 +109,7 @@ sub tpl(){
|
||||||
}else{
|
}else{
|
||||||
#if payone fails/error
|
#if payone fails/error
|
||||||
if($ctadr->{txt27} =~ /active|pending/){
|
if($ctadr->{txt27} =~ /active|pending/){
|
||||||
if($ctadr->{ct_name} && ($ctadr->{ct_name} =~ /PO-/ || $ctadr->{ct_name} =~ /TM-/) && $coo){
|
if($ctadr->{ct_name} && $ctadr->{ct_name} =~ /\w{2}-\w+/ && $coo){
|
||||||
my $webtarget = "_blank";
|
my $webtarget = "_blank";
|
||||||
my $dtext = "";
|
my $dtext = "";
|
||||||
if($varenv->{syshost} =~ /app/){
|
if($varenv->{syshost} =~ /app/){
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue