#!perl #!/usr/bin/perl use strict; use lib '.'; use CGI; use CGI::Carp qw(fatalsToBrowser set_message); use DBI; use JSON; use Digest::MD5 qw(md5 md5_hex md5_base64); use HTTP::Request; use HTTP::Request::Common; use Data::Dumper; # Status Codes: # 200: Everything is OK. Request succeeded # 400: Bad request (e.g. wrong parameters) # 403: Permission denied (wrong api login/key/signatures ...) # 404: Clients not found # 409: Conflict # 451: Unavailable For Legal Reasons #ENDPOINT: http://demo.wtspace.com:8081/ =pre grant all on cht_1.* to 'pos'@'localhost' identified by 'fbg4ips'; flush privileges; Triggers: DEFINER=`pos`@`localhost` functionS: 1. valid client -- check if there is a client with first name and last name in POS. prefer with is unique ID that is belonging to WP system . 2. create client 3. delete client 4. client info -- parameter: unique client id` 5. topup cash card 6. retrive balance. =cut my $dbuser = 'root'; my $dbpassword = 'fbg4ips'; my $dbhost = '127.0.0.1'; my $database = 'dial_1';#'cht_1'; my $clientgroup = 'wp'; my $merchent = 'POS'; my $secret = '6lwg6eb7kgn5wi3pk6x7lshzfvdye4jjqvlxy5ri5K'; my $q = CGI->new(); my $f; for( $q->param() ) { my @val = $q->param($_); for(@val){ s//>/gs; s/"/"/gs; s/\(/(/gs; s/\)/)/gs; s/\'/'/gs; }; $f->{$_} = @val>1 ? \@val : $val[0]; } # Logging CGI request - DEBUG #my $post = Dumper($f); #$post=~s/\r//g; #$post=~s/\$VAR1 = \{(.+)\};/$1/s; #$post=~s/\n+$//g; #print STDERR "POST data: $post"; out({"status"=>403, msg=>"Access denied."}) if $ENV && $ENV{REQUEST_METHOD} ne 'POST'; $f->{op} = "$1_$2" if $ENV{REQUEST_URI}=~/api\/(\w+)\/(\w+)/i; $f->{key}=$f->{api_key} if !$f->{key} && $f->{api_key}; my $signature = uc(md5_hex($merchent.':'.$secret.':'.$f->{datetime})); out({"status"=>403, msg=>"Invalid signature"}) unless $signature eq $f->{sign}; my $db = DataBase->new(); my $sub={ create_client => \&CreateClient, delete_client => \&DeleteClient, retrieve_balance=> \&RetrieveBalance, topup_balance => \&TopupBalance, valid_client => \&ValidClient, }->{ $f->{op} }; if($sub) { &$sub } else { out({"status"=>400, msg=>"Invalid operation"}); } sub CreateClient{ ############################### # UEL : /api/create/client # Parameters: # username varchar(50) # email varchar(50) # telephone varchar(12) # cellphone varchar(12) # address varchar(200) # postcode varchar(10) # ph_address varchar(200) # ph_postcode varchar(10) # loyalnumber varchar(20), # tax_number varchar(20) # @@@@@@@@@@@@@@@@@@@@@@@@@@@@@ # Return: password code ############################### out({"status"=>400, msg=>"client name is needed.$f->{username}"}) if !$f->{username}; #Contact info ..... local *get_password = sub { my @range = ('0'..'9'); my $x = int scalar @range; return join '', map $range[rand $x], 1..6||1; }; my $password = get_password(); $db->Exec("INSERT INTO tillclients SET shop_id=1, password=?, active=1, createddate=NOW(), f_status=1, created=NOW(), clientgroup=?, name=?, email=?, telephone=?, cellphone=?, address=?, address1=?, address2=?, address3=?, postcode=?, ph_address=?, ph_address1=?, ph_address2=?, ph_address3=?, ph_postcode=?, tax_number=?, loyalnumber=?, fax=?", $password, $clientgroup, $f->{username}, $f->{email}, $f->{telephone}, $f->{cellphone}, $f->{address}, $f->{address1}, $f->{address2}, $f->{address3}, $f->{postcode}, $f->{ph_address}, $f->{ph_address1}, $f->{ph_address2}, $f->{ph_address3}, $f->{ph_postcode}, $f->{tax_number}, $f->{loyalnumber}, $f->{fax} ); my $code = $db->getLastInsertId; $db->Exec("UPDATE tillclients SET code =? WHERE id=?",$code,$code); out({"status"=>200, "code"=>$code,"password"=>$password,msg=>"client created."}); } sub DeleteClient{ #Parameter: code out({"status"=>400, msg=>"no client code."}) unless $f->{code} ; out({"status"=>404, msg=>"no client with this code."}) unless $db->SelectOne("SELECT code FROM tillclients WHERE code=? LIMIT 1",$f->{code}); $db->Exec("DELETE FROM tillclients WHERE code=? ",$f->{code}); out({"status"=>200, msg=>"the client has been deleted."}); } sub RetrieveBalance{ #http://demo2.wtspace.com:84/api/retrieve/balance #Parameters: code =pre { "server_time": "2023-11-02 23:43:39", "status": 200, "balance": 1605.4, "msg": "OK", "currency": "R" } =cut out({"status"=>400, msg=>"no client code."}) unless $f->{code} ; my $bal = $db->SelectRow("SELECT tillclients.*, bal.entity_debit, bal.entity_credit, tillclients.creditlimit, bal.entity_credit - bal.entity_debit credit_balance, tillclients.creditlimit + IF(bal.entity_credit IS NULL OR bal.entity_debit IS NULL,0, bal.entity_credit - bal.entity_debit) available_credit FROM tillclients tillclients left join account_balance_entity bal on bal.account = 1 and entityid = tillclients.id where tillclients.id = ?",$f->{code}); my $balance = $bal->{available_credit} * -1; $balance += $bal->{creditlimit}; out({"status"=>200, msg=>"OK",balance=>formatNumber($balance),currency=>'R'}); } sub ValidClient{ # http://demo2.wtspace.com:84/api/valid/client # Parameter : code =pre { "server_time": "2023-11-02 23:47:21", "status": 200, "msg": "client is valide." } =cut out({"status"=>400, msg=>"no client code."}) if !$f->{code} ; my $client = $db->SelectRow("SELECT code FROM tillclients WHERE code=? LIMIT 1",$f->{code}); if($client){#only return 1 out({"status"=>200, msg=>"client is valide.",client_status=>$client->{active}==1?'active':'inactive'}); } out({"status"=>200, msg=>"client is not valid."}); } sub TopupBalance{ # http://demo2.wtspace.com:84/api/topup/balance # Parameters: # code int(10) # amount decimal(11,2) =pre { "status": 200, "msg": "top up successfully.", "server_time": "2023-11-03 00:48:03" } =cut #trtype - EFT my $trtype = 'EFT'; #entityid -- client id OR code #credit out({"status"=>400, msg=>"parameters missed."}) if !$f->{code}||!$f->{amount} ; my $entityid = $f->{code}; my $credit = sprintf("%.02f",$f->{amount}); #print "Content-type:text/html\n\n$f->{code},$credit";exit; $db->Exec("INSERT INTO `accounts` SET `account` =1, `entityid` =?, `debit` =?, `credit` =0, `description`='', `document`='', `stamp`=current_timestamp, `date`=NOW(), `transaction_type`=?, `userid`=1, `tillinvoice_id`=0, `banked`=1 ", $entityid, $credit, $trtype ); out({"status"=>200, msg=>"top up successfully."}); } sub out { my $data = shift; $data->{server_time} = sprintf("%d-%02d-%02d %02d:%02d:%02d", getTime() ); print"Content-type:application/json\n\n".JSON::encode_json($data); exit; } sub getTime { my ($time) = @_; my @t = $time ? localtime( $time ) : localtime(); return ( sprintf("%04d",$t[5]+1900), sprintf("%02d",$t[4]+1), sprintf("%02d",$t[3]), sprintf("%02d",$t[2]), sprintf("%02d",$t[1]), sprintf("%02d",$t[0]) ); } sub randchar { my @range = ('0'..'9','a'..'z'); my $x = int scalar @range; join '', map $range[rand $x], 1..shift||1; } sub formatNumber{ my $num = shift; $num = int($num * 100)/100; if($num !~/\./){ $num = $num . '.0'; } return $num; } package DataBase; #pain for old method. so, introduce this package.....:) use DBI; sub new{ my ($class, %opts) = @_; my $self = { %opts }; bless $self,$class; $self->InitDB; return $self; } sub inherit{ my $class = shift; my $dbh = shift; my $self={ dbh=>undef }; bless $self,$class; $self->{dbh} = $dbh; return $self; } sub dbh{shift->{dbh}} sub InitDB{ my $self = shift; $self->{dbh}=DBI->connect("DBI:mysql:database=$database;host=$dbhost;", $dbuser,$dbpassword) || die ("Can't connect to Mysql server."); $self->Exec("SET sql_mode = ''"); $self->{'exec'}=0; $self->{'select'}=0; } sub DESTROY{ shift->UnInitDB(); } sub UnInitDB{ my $self=shift; if($self->{dbh}) { if($self->{locks}) { $self->Unlock(); } $self->{dbh}->disconnect; } $self->{dbh}=undef; } sub Exec { my $self=shift; $self->{dbh}->do(shift,undef,@_) || die"Can't exec:\n".$self->{dbh}->errstr; $self->{'exec'}++; } sub SelectOne { my $self=shift; my $res = $self->{dbh}->selectrow_arrayref(shift,undef,@_); die"Can't execute select:\n".$self->{dbh}->errstr if $self->{dbh}->err; $self->{'select'}++; return $res->[0]; }; sub SelectRow { my $self=shift; my $res = $self->{dbh}->selectrow_hashref(shift,undef,@_); die"Can't execute select:\n".$self->{dbh}->errstr if $self->{dbh}->err; $self->{'select'}++; return $res; } sub Select { my $self=shift; my $res = $self->{dbh}->selectall_arrayref( shift, { Slice=>{} }, @_ ); die"Can't execute select:\n".$self->{dbh}->errstr if $self->{dbh}->err; return undef if $#$res==-1; my $cidxor=0; for(@$res) { $cidxor = $cidxor ^ 1; $_->{row_cid} = $cidxor; } $self->{'select'}++; return $res; } sub SelectARef { my $self = shift; my $data = $self->Select(@_); return [] unless $data; return [$data] unless ref($data) eq 'ARRAY'; return $data; } sub getLastInsertId { return shift->{ dbh }->{'mysql_insertid'}; } 1;