Web retail application óõíÝ÷åéá
Êáé áíôß íá ðçãáßíïõìå óôï supermarket ãéá íá øùíßóïõìå ìðïñïýìå íá øùíßæïõìå áðü ôï óðßôé ìáò ìå ðáñáããåëßåò ìÝóù ôïõ internet. Áíôß ãéá barcode scanner åðéëÝãïõìå ôá åßäç ìÝóù åéêüíùí. Ðëçñþíïõìå ìå ðéóôùôéêÞ êÜñôá, åéóÜãïíôáò ôá óôïé÷åßá ìáò óôï áóöáëÝò site ôçò ôñÜðåæáò êáé ï Ýìðïñïò ëáìâÜíåé áðëÜ ôçí åðéâåâáßùóç ôçò ðëçñùìÞò.
Ç áñ÷éôåêôïíéêÞ ôïõ ëïãéóìéêïý ðáñáìÝíåé ç ßäéá. Ìå åëÜ÷éóôç ðñïóðÜèåéá ïé 2 ëýóåéò èá ÷ñçóéìïðïéïýí ôïí ßäéï server. Êáé ïé êåñäéóìÝíïé ðüíôïé, ìáæß ìå Üëëá ðñïùèçôéêÜ ìçíýìáôá èá êáôáöèÜíïõí ìå sms. Ç ìåãáëýôåñç ðëÝïí ÅëëçíéêÞ åôáéñåßá, ìå ãáëëéêü Üñùìá, óôñÝöåôáé óôï internet óáí íÝï ôñüðï áãïñþí ãéá ôï supermarket. Ìßá êåíôñéêÞ áðïèÞêç èá åîõðçñåôåß ôéò ðáñáããåëßåò, ôá êáôáóôÞìáôá èá ìéêñýíïõí (ëéãüôåñïé ðåëÜôåò) êáé ôá êüóôç èá ìåéùèïýí. Êáé âÝâáéá üóï ðåñéóóüôåñï ìÝíïõìå óôï óðßôé ôüóï êáëýôåñá.[V]
ÔñÜðåæá Ýêäïóçò ôçò êÜñôáò (issuer) êáé ôñÜðåæá ôïõ EFT (aquirer).
Ôçí êÜñôá ìáò êáé ï óõíäåäåìÝíïò ìå áõôÞ ëïãáñéáóìüò ìáò ôçñåßôáé óå ìßá ôñÜðåæá Á. Ï áñéèìüò ôçò êÜñôáò (15 øçößá + 1 øçößï LUHN check digit ) ðáñáðÝìðïõí óôçí ôñÜðåæá Ýêäïóçò. Ôï ôåñìáôéêü, óôçí ãåíéêüôçôÜ ôïõ, áíÞêåé óå êÜðïéá Üëëç ôñÜðåæá  äéáöïñåôéêÞ áðü ôïí åêäüôç ôçò êÜñôáò ðïõ ÷ñçóéìïðïéïýìå. Ôï ôåñìáôéêü èá åîõðçñåôÞóåé áðåõèåßáò ôéò êÜñôåò ôçò ßäéáò ôñÜðåæáò  êáé èá óôåßëåé üëåò ôéò îÝíåò óõíáëëáãÝò óôçí VISA, MC, ÁÌÅ× êôë. ÁõôÝò ìå ôçí óåéñÜ ôïõ èá ôéò ðñïùèÞóïõí óôçí åêäüôñéá ôñÜðåæá Á, ðïõ îÝñåé ôï õðüëïéðï ôïõ ëïãáñéáóìïý ìáò êáé ç áðÜíôçóç èá áêïëïõèÞóåé ôçí áíôßèåôç äéáäéêáóßá.
ÁíÜëõóç & ó÷åäßáóç åíüò éäåáôïý (virtual) ISO8583 POS.
¸íá Üëëï äéáäåäïìÝíï ôñáðåæéêü ðñùôüêïëëï åßíáé ôï
SPDH.
Ðùò ðñï÷ùñÜìå ?. Äåí Ý÷ïõìå óýíïøç ãéá ôï SPDH. Èá ôï áãíïÞóïõìå Þ èá ëÜâïõìå óôïé÷åéþäç ðñüíïéá þóôå íá åßíáé åýêïëç ç ðëÞñçò õðïóôÞñéîÞ ôïõ óôçí óõíÝ÷åéá ?
ÅðéëÝãù íá ôï õðïóôçñßîù. Îå÷íÜù ôéò éäéáéôåñüôçôåò ôïõ ISO8583 êáé óõãêåíôñþíïìáé óôéò ëåéôïõñãéêÝò ðñïäéáãñáöÝò. Ôé ðñÝðåé íá êÜíåé Ýíá ôåñìáôéêü ãéá ðéóôùôéêÝò êÜñôåò ? Êáé ôá äýï ðñùôüêïëëá Ý÷ïõí ó÷åäéáóèåß ãéá íá éêáíïðïéïýí áõôÝò áêñéâþò ôéò áíÜãêåò.
Èá ïñßóïõìå ìéá éäåáôÞ (abstract) êëÜóç ÔBaseEFTPos ìå ìåèüäïõò ôéò ÷ñçìáôïïéêïíïìéêÝò õðçñåóßåò (ðïõ åßíáé áíåîÜñôçôåò ôïõ ðñùôïêüëëïõ) êáé óôçí óõíÝ÷åéá ôá 2 ðáéäéÜ ôçò ÔSPDHEFT êáé TISO8583EFT ðïõ õëïðïéïýí áõôÝò ôéò õðçñåóßåò ìå ôçí ÷ñÞóç êÜèå ðñùôïêüëëïõ.
Ç ÔBaseEFTPos Ý÷åé ìåèüäïõò
Áñ÷éêïðïßçóç - Initialization
ÐñïÝãêñéóç - Áuthorization (óôïé÷åßá êÜñôáò, ðïóü) óå Îåíïäï÷åßá, åíïéêéÜóåéò áõôïêéíÞôùí
Ðþëçóç - Sale(óôïé÷åßá êÜñôáò, ðïóü)
Áêýñùóç Ðþëçóçò - Void Sale (óôïé÷åßá êÜñôáò, ðïóü)
ÅðéóôñïöÞ - Refund (óôïé÷åßá êÜñôáò, ðïóü) Óå Üëëç ÷ñïíéêÞ óôéãìÞ
Áêýñùóç ÅðéóôñïöÞ – Void Refund(óôïé÷åßá êÜñôáò, ðïóü)
Ïñéóôéêïðïßçóç - Finalization
Ç êëÜóç TISO8583EFT ðñÝðåé
A. íá õëïðïéåß ôéò ìåèüäïõò ôïõ TBaseEFT
B. íá ìðïñåß íá áíáêáëåß êáé íá óþæåé ôá óôïé÷åßá ôùí óõíáëëáãþí óå ìéá âÜóç äåäïìÝíùí
Ã. íá ìïñöïðïéåß êáé íá áíáëýåé ISO8583 ìçíýìáôá
Ä. íá áíôáëëÜóåé, ìÝóù tcp/ip, ISO8583 ìçíýìáôá ìå ôçí ôñÜðåæá.
Å. íá åëÝã÷åé êáé íá õëïðïéåß ôïõò áíôéëïãéóìïýò (reversals)
Æ. íá ôçñåß êáé íá êëåßíåé ôï batch
Ç. íá îáíáóôÝëíåé ôï batch
Ç êëÜóç TSPDHEFT ðñÝðåé
Á. íá õëïðïéåß ôéò ìåèüäïõò ôïõ TBaseEFT
Â. íá ìðïñåß íá áíáêáëåß êáé íá óþæåé ôá óôïé÷åßá ôùí óõíáëëáãþí óå ìéá âÜóç äåäïìÝíùí
Ã. íá ìïñöïðïéåß êáé íá áíáëýåé SPDH ìçíýìáôá
Ä. íá áíôáëëÜóåé, ìÝóù x25 SPDH ìçíýìáôá ìå ôçí ôñÜðåæá.
Å. íá åëÝã÷åé êáé íá õëïðïéåß ôïõò áíôéëïãéóìïýò (reversals)
Æ. íá ôçñåß êáé íá êëåßíåé ôï batch
Ïé óçìáíôéêüôåñåò äéáöïñÝò óôá 2 ôñáðåæéêÜ ðñùôüêïëëá åßíáé ç ëïãéêÞ ôïõ reversal êáé ôï êëåßóéìï batch. Óôï SPDÇ ôçñïýíôáé êáé óõãêñßíïíôáé ôá óýíïëá êáé óå ðåñßðôùóç óöÜëìáôïò ç äéáäéêáóßá óôáìáôÜåé êáé áðáéôåß áíèñþðéíç åðÝìâáóç.
ÊëÜóåéò
¸÷ïõìå ïñßóåé ôçí éåñáñ÷ßá ðïõ áðïôõðþíåôáé óôï ðáñáêÜôù ó÷Þìá.
Ï Ýîù êüóìïò âëÝðåé ôéò õðçñåóßåò ðïõ ðáñÝ÷åé ôï TBasePos. ÁõôÝò áðáéôïýí ôçí åðéëïãÞ åíüò ôåñìáôéêïý, Ýíá ðïóü, ìéá êÜñôá êáé ìßá åíÝñãåéá, äëä, ï Ýìðïñïò ïëïêëÞñùóå ìéá óõíáëëáãÞ ðëçñùìÞò óôï ôåñìáôéêü ôçò ôñÜðåæáò Á ãéá ôï ðïóü ×.
Ôï ôåñìáôéêü ÄÅÍ Ý÷åé áðåõèåßáò ðñüóâáóç óôá äåäïìÝíá ôçò âÜóçò äåäïìÝíùí. ¸ôóé ìðïñþ íá ÷ñçóéìïðïéÞóù flat áñ÷åßá Þ oracle Þ mysql ÷ùñßò íá åðçñåÜóù ôçí ëåéôïõñãéêüôçôá ôïõ TBaseEft.
Ãéá íá áðïìïíþóù ôï TBasePos áðü ôçí âÜóç äåäïìÝíùí äçìéïõñãþ Ýíá ìßá åíäéÜìåóç êëÜóç dbHandler. ÁõôÞ åðéêïéíùíåß ìå ôï TBasePos êáé áíôáëëÜóåé äåäïìÝíá ìå ÷ñÞóç ôùí êëÜóåùí NeutralTerm êáé NeutralTrn. ÅðéðëÝïí ãíùñßæåé ðþò íá ôéò «ãåìßæåé» ìå óôïé÷åßá áðü ôçí âÜóç äåäïìÝíùí.
Óôçí âÜóç äåäïìÝíùí äçìéïõñãþ ðßíáêåò ãéá üëåò ôéò ïíôüôçôåò ðïõ ÷ñçóéìïðïéïýìå. Ïé áíôßóôïé÷åò êëÜóåéò Ý÷ïõí óáí attributes ôá ðåäßá ôçò âÜóçò êáé êëçñïíïìïýí ôéò ìåèüäïõò ôïõò áðü ôçí êëÜóç dbTable.
ÌÝ÷ñé ôþñá Ýìåéíá óôçí ó÷åäßáóç. Ìçí ãåëáóôåßôå. Äåí Ý÷åé óçìáóßá ðïõ ôï software åßíáé soft. Äåí Ý÷åé óçìáóßá ðïõ áëëÜæåé ó÷åôéêÜ åýêïëá. Ç ó÷åäßáóç åßíáé ôï ðñþôï âÞìá óå êÜèå project. Ôï cash flow åßíáé ôï äåýôåñï. Ç õëïðïßçóç Ýðåôáé.
Äåí áíáöÝñù êÜôé ãéá áóöÜëåéá êáé passwords êáé encryption. Èåùñþ üôé áõôÝò ïé åöáñìïãÝò «æïõí» óå áóöáëÞ ðåñéâÜëëïíôá. ÅðéðëÝïí äåí áíáöÝñïìáé óôá êëåéäéÜ ðïõ áíôáëëÜóóïíôáé ãéá ôçí êùäéêïðïßçóç êáé áðïêùäéêïðïßçóç ôïõ PIN. Ôï èÝìá ôïõ Chip åßíáé áðü ìüíï ôïõ Ýíá èçñßï
Ìçíýìáôá ôýðïõ ISO8583.
¸íá ìÞíõìá áðïôåëåßôáé áðü ôçí óýíèåóç ôùí åðéìÝñïõò ðåäßùí ôïõ. ÊÜèå ìÞíõìá Ý÷åé ìéá åðéêåöáëßäá Ýíá ðåñéå÷üìåíï êáé ðéèáíÜ Ýíá êùäéêü åðáëÞèåõóçò (crc).
ÓõíÞèùò ôá ðåäßá áðïèçêåýïíôáé ôï Ýíá ìåôÜ ôï Üëëï êáé ÷ùñßæïíôáé ìå Ýíá ÷áñáêôÞñá (Field Separator).
¼ôáí üìùò Ý÷åéò ìéá áðëÞ ôçëåöùíéêÞ ãñáììÞ êáé Ýíá modem 2400 baud êÜèå åðéðëÝïí byte ìåôñÜåé. Ç ÷ñüíïò åðéêïéíùíßáò åßíáé áíÜëïãïò ìå ôï ìÝãåèïò ôïõ ìçíýìáôïò.
ÐñÝðåé ï ó÷åäéáóôÞò íá âñåé ôñüðï þóôå íá ìåôáöÝñåé ìüíï üóá ðåäßá áðáéôïýíôáé ôçí öïñÜ. ¸ôóé åéóÜãåôáé ôï bitmap. ×ñçóéìïðïéïýìå ôá bits áðü 8 óõíå÷üìåíá bytes ãéá íá äåßîïõìå ðéá ðåäßá, (1..64) õðÜñ÷ïõí Þ ü÷é.
Ôo ISO8583 ìÞíõìá áðïôåëåßôáé áðü ascii ÷áñáêôÞñåò êáé áñ÷ßæåé ìå êÜðïéá óôáèåñÜ ðåäßá, ôï primary bitmap (óå äåêáåîáäéêÞ áðåéêüíéóç) êáé óôçí óõíÝ÷åéá ôá ðåäßá ôïõ.
ÅðåéäÞ üìùò ôá 64 ðåäßá äåí Þôáí áñêåôÜ ÷ñçóéìïðïéÞèçêå êáé Ýíá 2ï bitmap (secondary). Ôï 1o bit ôïõ primary bitmap óçìáôïäïôïýóå ôçí ýðáñîç Þ ü÷é ôïõ 2ïõ bitmap êáé êáôÜ óõíÝðåéá ôçí ýðáñîç 64 Þ 128 ðåäßùí óôï ìÞíõìá.
Êþäéêáò:
function TISO8583.FieldExists(fieldNo: integer): boolean;
begin
if fieldNo>64 then
result:=TestBit(PrimaryBitmap,1) and TestBit(SecondaryBitmap,fieldNo-64)
else
result:=TestBit(PrimaryBitmap,fieldNo)
end;
ÊÜèå ðåäßï, áðåéêïíßæåôáé óå ascii áëëÜ Ý÷åé ôýðï êáé ìÞêïò. Ðùò åëÝã÷ïõìå 128 ðåäßá ?. ¸íá ìåãÜëï case statement êáé ôåëåéþóáìå. ¸íáò Üëëïò ôñüðïò åßíáé íá ðåñéãñÜøïõìå ôéò éäéüôçôåò ôùí ðåäßùí êáé íá åëÝã÷ïõìå êáèïäçãïýìåíïé áðü áõôÝò.
Êþäéêáò:
type TNibble = 0..15;
T8583FieldTypes = (ftb,ftn,ftx_n,ftns,fta,ftan,ftans,ftz,fta_n);
T8583FieldFormat = (ffNone,ffLLVAR,ffLLLVAR,ffMMDDhhmmss,
ffhhmmss,ffMMDD,ffYYMM,ffYYMMDD,ffx,ffb);
T8583FieldDef = packed record
bit:byte;
kind:T8583FieldTypes;
len:word;
opt:T8583FieldFormat;
end;
T8583FieldDef = packed record
bit:byte;
kind:T8583FieldTypes;
len:word;
opt:T8583FieldFormat;
end;
const FieldDefs : array[1..128] of T8583FieldDef =
((bit: 1; kind: ftb; len: 1; Opt:ffNone),
(bit: 2; kind: ftn; len: 19; Opt:ffLLVAR),
(bit: 3; kind: ftn; len: 6; Opt:ffNone),
..
(bit: 7; kind: ftn; len: 10; Opt:ffMMDDhhmmss),
..
(bit: 12; kind: ftn; len: 6; Opt:ffhhmmss),
(bit: 13; kind: ftn; len: 4; Opt:ffMMDD),
(bit: 14; kind: ftn; len: 4; Opt:ffYYMM),
(bit: 15; kind: ftn; len: 4; Opt:ffMMDD),
..
(bit: 28; kind:ftx_n; len: 8; Opt:ffx),
..
Äéáöïñåôéêïß ôýðïé ðåäßùí ìå óôáèåñü Þ ìåôáâëçôü ìÞêïò, óôç áðïóôïëÞ áëëÜ êáé óôçí ëÞøç. Ðåäßá ìÝóá óå ðåäßá.
Êþäéêáò:
procedure TISO8583.SetField(fieldNo: integer;const Value: string);
var ok:boolean;
begin
with FieldDefs[fieldNo] do
begin
case opt of
ffLLVAR,
ffLLLVAR : ok:=length(value)<=len;
ffx : ok:=length(Value)=len+1;
ffb : ok:=length(value)=(len div 8)*2
else
ok:=length(Value)=len;
end;
if not ok then
raise Exception.CreateFmt('Invalid Field %d length %d vs %d',
[fieldNo,length(value),len]);
case kind of
ftb : ok:=isHex(Value);
ftn : begin
ok:=isN(Value);
if ok then
case opt of
ffMMDDhhmmss : ok:=isMMDD(copy(value,1,4)) and
isHHMMSS(copy(value,5,6));
ffhhmmss : ok:=isHHMMSS(value);
ffMMDD : ok:=isMMDD(value);
ffYYMM : ok:=isYYMM(value);
ffYYMMDD : ok:=isYYMMDD(value);
end
end;
ftx_n : ok:=(value[1] in ['C','D']) and
isN(copy(Value,2,length(value)-1));
ftns :;
fta :ok:=isA(Value);
ftan :ok:=isAN(Value);
ftans :ok:=isANS(Value);
ftz :;
fta_n :ok:=isN(Value) or isA(value); // a or n
end;
if not ok then
raise Exception.CreateFmt('Invalid Field data %d [%s]',
[FieldNo,Value]);
end;
// Valid field value, store it
fFields[pred(fieldNo)]:=value;
if (fieldNo>64) then
begin
SetBit(SecondaryBitmap,fieldNo-64);
SetBit(PrimaryBitmap,1);
end
else
SetBit(PrimaryBitmap,fieldNo)
end;
TISO8583 = class
private
fFields:TStringList;
fID:string;
fMTI: string;
PrimaryBitmap : array[1..8] of byte; // 16 hex bytes
SecondaryBitmap : array[1..8] of byte;
function GetData: string;
procedure SetData(Value: string);
function GetField(fieldNo: integer): string;
procedure SetField(fieldNo: integer; const Value: string);
function AsString(fieldNo:integer;value:int64):string;
procedure SetBit(var buf;bitNo: integer);
function TestBit(var buf;bitNo: integer): boolean;
protected
function isN(value:string):boolean;
function isANS(value:string):boolean;
function isA(value:string):boolean;
function isAN(value: string): boolean;
..
constructor Create(const aMerchantId,aTerminalId,
aAcquirerId : string); overload; virtual;
public
constructor Create; reintroduce; overload;
constructor Create(const msg:string); overload;
destructor Destroy; override;
procedure AssignTo(source:TISO8583);
function FieldExists(fieldNo:integer):boolean;
procedure Clear; virtual;
property MTI: string read fMTI write fMTI;
property Data:string read GetData write SetData;
property Fields[fieldNo:integer]:string read GetField
write SetField;
end;
ÈÝëïõìå íá óðÜóïõìå Ýíá ascii iso8583 ìÞíõìá óôá ðåäßá ðïõ ôï ó÷çìáôßæïõí.
Êþäéêáò:
iso8583 := TISO8583.Create;
iso8583.Data:=msg;
procedure TISO8583.SetData(Value: string);
var i,ilen:integer;
s:string;
p:pByte;
w:pword;
b:byte;
begin
Clear;
fID:=copy(value,1,6); delete(value,1,6);
fMTI:=copy(value,1,4); delete(value,1,4);
BitCopy(value, PrimaryBitmap); delete(value,1,16);
if TestBit(PrimaryBitmap,1) then begin
BitCopy(value, SecondaryBitmap); delete(value,1,16);
end;
for i:=1 to 128 do // skip Primary and Secondary bitmaps
if (i<>1) and (i<>65) and fieldExists(i) then
with FieldDefs[i] do begin
case Opt of
ffLLVAR : begin
ilen:=StrToInt(copy(value,1,2));
delete(value,1,2);
end;
ffLLLVAR: begin
ilen:=StrToInt(copy(value,1,3));
delete(value,1,3);
end;
ffx : ilen:=len+1;
ffb : ilen:=(len div 8)*2;
else
{ ffMMDDhhmmss, ffhhmmss, ffMMDD, ffYYMM, ffYYMMDD, ffNone :}
ilen:=len;
end;
s:=copy(value,1,ilen); delete(value,1,ilen);
// áöïý ðÞñáìå ôï ðåñéå÷üìåíï ôïõ ðåäßïõ
// ôþñá áò ôï áðïèçêåýóïõìå
// property Fields[FieldNo:integer]:string ... write SetField;
Fields[i]:=s;
end;
end;
Óõíå÷ßæåôáé…