Σελίδα 1 από 2 12 ΤελευταίαΤελευταία
Εμφάνιση αποτελεσμάτων 1 μέχρι 10 από 13

Θέμα: ISO8583 - Τραπεζικό πρωτόκολλο

  1. #1
    Μέλος
    Ημερομηνία εγγραφής
    Mar 2012
    Θέση
    Athens, , Greece.
    Ιδιότητα:
    Αγνωστη
    Απαντήσεις
    99

    ISO8583 - Τραπεζικό πρωτόκολλο


    Ηλεκτρονικό κατάστημα ειδών θέρμανσης και κλιματισμού

    Σύνοψη

    Πληρώνουμε με κάρτα ή κάνουμε ανάληψη χρημάτων από το ATM. Ανησυχούμε για ορθότητα της συγκεκριμένης συναλλαγής ? Μάλλον όχι. Ίσως να ανησυχούμε για το αν κάποιος τρίτος μας κλέψει την κάρτα και το pin και μας χρεώσει τις δικές του αγορές. Αν κάνουμε αγορές στο internet επιβάλλεται να χρησιμοποιούμε προπληρωμένη κάρτα «φορτωμένη» με ποσό ίσο με την αγορά μας.

    Το πρωτόκολλο ISO8583 (http://en.wikipedia.org/wiki/ISO_8583) είναι ένα τραπεζικό πρωτόκολλο που χρησιμοποιείται όταν κάνουμε οικονομικές συναλλαγές σε ATM, EFT, web banking κτλ και καθορίζει

    1. Τις δύο άκρες της επικοινωνίας. Το ένα άκρο (τερματικό) που εκκινεί την συναλλαγή (EFT, ATM ή μια εφαρμογή σε ένα PC) και το δεύτερο άκρο, την τράπεζα (τον processor για την ακρίβεια). Το κανάλι επικοινωνίας μπορεί να είναι μια απλή τηλεφωνική γραμμή συνδεδεμένη σε ένα modem και μια σειριακή θύρα ή μια TCP/IP γραμμή.

    2. Κάθε τερματικό έχει δικό του μοναδικό κωδικό TerminalID και τον κωδικό του εμπόρου MerchantID, ο λογαριασμός του οποίου θα πιστωθεί από την αγορά με αντίστοιχη χρέωση του λογαριασμού της κάρτας. Στα ATMs η συναλλαγή ανάληψης αφορά μόνο ένα λογαριασμό.

    3. Κάθε τερματικό υπάρχει δηλωμένο (λογικά) και στην τράπεζα. Κάθε κίνηση στην μία άκρη αντιγράφεται στο λογικό τερματικό στη τράπεζα.

    4. Την μορφή και το περιεχόμενο των μηνυμάτων που ανταλλάσσονται. Η μορφή των μηνυμάτων είναι μια απλή λεπτομέρεια.

    5. Το τερματικό που εκκινεί την συναλλαγή είναι και ο απόλυτος κριτής της επιτυχίας ή της αποτυχίας της. Επιτυχημένη συναλλαγή είναι αυτή που ο client έχει αποστείλει μήνυμα και έχει λάβει και καταγράψει την απάντηση του Server. Η συναλλαγή μπορεί να είναι επιτυχημένη επικοινωνιακά αλλά με αρνητική απάντηση ως προς το ερώτημα (αν πχ δεν υπάρχουν χρήματα για ανάληψη).

    6. Χειρισμό κάθε αποτυχίας επικοινωνίας από το τερματικό.

    Σε κάθε TCP/IP συναλλαγή εκτελούνται τα εξής βήματα.
    • Σύνδεση του τερματικού με τον server (τράπεζα). Η αδυναμία σύνδεσης σημαίνει αδυναμία εκτέλεσης της συναλλαγής και δεν είναι σφάλμα επικοινωνίας.
    • Αποστολή ISO8583 μηνύματος από το τερματικό στο server
    • Λήψη αιτήματος από τον server.
    • Επεξεργασία αιτήματος από τον server.
    • Αποστολή της ISO8583 απάντησης από τον server στον client
    • Παραλαβή απάντησης από τον client.
    • Αποσύνδεση του server με την ολοκλήρωση της αποστολής της απάντησης.
    • Επεξεργασία απάντησης από τον client.

    Σε κάθε σημείο μπορεί η επικοινωνία να διακοπεί. Μπορεί η απάντηση να έχει παραληφθεί από το τερματικό αλλά για οποιοδήποτε λόγο (διακοπή ρεύματος) να μην ολοκληρώθηκε η καταγραφή και η επεξεργασία της.

    Μετά από κάθε αποτυχημένη επικοινωνία, το τερματικό προσπαθεί να αντιλογίσει (reverse) την τελευταία αποτυχημένη συναλλαγή. Η άλλη πλευρά (τράπεζα) γνωρίζει ποια είναι η τελευταία συναλλαγή του συγκεκριμένου τερματικού που έχει λάβει. Και πράττει ανάλογα. Ακυρώνει την τελευταία συναλλαγή ή αγνοεί την εντολή και επιστρέφει επιτυχία.
    Τα μηνύματα αντιλογισμού δεν αντιλογίζονται αλλά επαναλαμβάνονται μέχρι να επιτύχουν.

    7. Την τήρηση αρχείου συναλλαγών στο τερματικό (batch) και κλείσιμο του batch, διαδικασία που εκτελείται συνήθως στο τέλος της ημέρας. Για κάθε επιτυχημένη συναλλαγή αυξάνεται ένα μετρητής συναλλαγών και ένας αθροιστής αξιών. Το κλείσιμο του batch αποστείλει στον server τα σύνολα (τον αριθμό και την αξία των συναλλαγών) που γνωρίζει το τερματικό. Ο server τα συγκρίνει με τα σύνολα που τηρεί για το συγκεκριμένο τερματικό. Αν τα σύνολα συμφωνούν, το batch κλείνει επιτυχώς, ανοίγει ένα νέο άδειο και η διαδικασία επαναλαμβάνεται.
    Για κάποιο λόγο τα σύνολα ανάμεσα στα δύο άκρα δεν συμφωνούν. Τότε το τερματικό, το σημείο δηλαδή που έγιναν οι συναλλαγές και υπάρχουν αποδεικτικά vouchers, στέλνει εξαρχής όλες τις συναλλαγές του batch.
    Η διαδικασία τελειώνει όταν συμφωνήσουν τα σύνολα.

    Κρίσιμη εφαρμογή

    Στο modbus πρότεινα μερικές επαναλήψεις στη αποστολή του μηνύματος, για να ανταλλάξουμε δεδομένα σε περίπτωση σφαλμάτων.

    Στο ISO8583 oι απαιτήσεις επιβάλουν τον χειρισμό σφαλμάτων στην διαδικασία.

    1. Τηρούνται δύο αντίγραφα των συναλλαγών, στο τερματικό και στη τράπεζα.
    2. Σε οποιοδήποτε σφάλμα επικοινωνίας η συναλλαγή αντιλογίζεται (διαγράφεται).
    3. Η συναλλαγή αντιλογισμού επαναλαμβάνεται έως ότου πετύχει.
    4. Στο κλείσιμο batch ελέγχονται τα σύνολα των συναλλαγών του τερματικού και των συναλλαγών της τράπεζας.
    5. Σε διαφωνία συνόλων το τερματικό "αφέντης" στέλνει ξανά τις συναλλαγές.

    Συνεχίζεται…

  2. #2
    Μέλος
    Ημερομηνία εγγραφής
    Mar 2012
    Θέση
    Athens, , Greece.
    Ιδιότητα:
    Αγνωστη
    Απαντήσεις
    99
    Που αλλού θα μπορούσαμε να χρησιμοποιήσουμε μια τέτοια σχεδίαση ?

    Ίσως να είχατε χρησιμοποιήσει τα παλιά VT100 character terminals συνδεδεμένα σε unix servers. Το unix δημιουργούσε ένα process για κάθε συνδεδεμένο (logged in) τερματικό.
    Το «χαζό» τερματικό έστελνε τις πληκτρολογήσεις στο unix, η εφαρμογή λάμβανε και αφού επεξεργαζόταν τα δεδομένα, έστελνε πίσω μηνύματα στην οθόνη ή τον εκτυπωτή του τερματικού.

    Η διαδικασία της πώλησης σε ένα super market μπορούσε να υλοποιηθεί εύκολα και δεν υπήρχε πότε πρόβλημα ενημέρωσης των κερδισμένων πόντων από την τελευταία αγορά. Όλα τα δεδομένα ήταν σε ένα σημείο (unix host) προσβάσιμο από κάθε ενδιαφερόμενο.
    Μπορούσες να συνδέσεις ένα barcode scanner, στη σειριακή πόρτα του τερματικού και τα barcodes που διάβαζες «ταξίδευαν» απευθείας για επεξεργασία στο unix. Με ένα modem στα 2400 baud μπορούσες να πουλάς σε κατάστημα στη Κομοτηνή με τον unix server στην Αθήνα.

    Κάναμε κάποιους κύκλους, εκσυγχρονισθήκαμε [:0], εγκαταστήσαμε στα ταμείο POSes με τοπική επεξεργασία και τοπικά δεδομένα. Και κάθε μεταβολή δεδομένων (νέα είδη, αλλαγές τιμών, κερδισμένοι πόντοι από αγορές) έπρεπε να διανεμηθούν σε όλα τα ταμεία της αλυσίδας (στο κατάστημα, την πόλη, τον νομό..). Και απαιτούσαμε δικτυακή υποδομή με ικανοποιητικό bandwidth ώστε μέσω ενός κεντρικού server να νέα δεδομένα να φτάσουν σε όλους τους παραλήπτες. Και, λόγω της υψηλής τεχνολογίας, οι πόντοι που κερδίσαμε σήμερα, ήταν διαθέσιμοι προς εξαργύρωση την επόμενη μέρα.

    Και ξαναγυρνάμε στην αρχή…

    Web retail Application

    O φυλλομετρητής συνδέεται με ένα Web Server και δημιουργεί ένα session με χρήση cookies.
    O browser δέχεται το barcode από τον usb barcode scanner του πάγκου.
    O browser αποστέλλει το barcode και πιθανά την ποσότητα στο Web Server και λαμβάνει πίσω κωδικό, περιγραφή είδους, τιμή μονάδος, έκπτωση και συνολική αξία.
    O browser αποθηκεύει τοπικά, σε ένα xml island, την πληροφορία που μόλις έλαβε και αθροίζει την ποσότητα και την αξία των ειδών.
    O browser στέλνει μόνο τα σύνολα στο WebServer για συμφωνία και εκτύπωση της απόδειξης. Ο WebServer τα συγκρίνει με τα σύνολα που τηρεί για το συγκεκριμένο browser (τερματικό) και απόδειξη (batch)

    Η τοπική TCP/IP ΕΑΦΔΣΣ δέχεται το κείμενο της απόδειξης από τον Web server και επιστρέφει την ψηφιακή υπογραφή (SHA1 digest).

    Ο Web Server εκτυπώνει σε τοπικό TCP/IP θερμικό εκτυπωτή την απόδειξη με την ψηφιακή υπογραφή.

    Προσπάθησα να τονίσω την σχεδιαστική αρχή που «κρύβεται» στο ISO8583. Στην συνέχεια, μέσω Λαμίας το ομολογώ, να περιγράψω την χρήση της σε ένα σημερινό πρόβλημα.

    Η συνέχεια έχει κλάσεις, μηνύματα και ολίγον SPDH. Stay tuned..

    ΥΓ. Έγραψα ότι στην περίπτωση του ΑΤΜ υπάρχει μόνο ένας λογαριασμός. Είναι λάθος. Στο διπλογραφικό σύστημα υπάρχει πάντα ένας λογαριασμός που χρεώνεται και ένας που πιστώνεται. Βέβαια υπάρχει και η δημιουργική λογιστική που υπηρετεί δημιουργικούς ανθρώπους και παράγει αξίες από αέρα.

  3. #3
    Μέλος
    Ημερομηνία εγγραφής
    Mar 2012
    Θέση
    Athens, , Greece.
    Ιδιότητα:
    Αγνωστη
    Απαντήσεις
    99
    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;
    Συνεχίζεται…

  4. #4
    Μέλος
    Ημερομηνία εγγραφής
    Mar 2012
    Θέση
    Athens, , Greece.
    Ιδιότητα:
    Αγνωστη
    Απαντήσεις
    99
    Μηνύματα τύπου SPH.
    Και εδώ έχουμε ανάγκη να σχηματίσουμε μηνύματα με μεταβλητό αριθμό πεδίων.
    Κάθε πεδίο έχει για όνομα ένα ascii χαρακτήρα. Τα πεδία χωρίζονται μεταξύ τους με τον χαρακτήρα FS (0x1C). Ένα SPDH μήνυμα αποτελείται από την επικεφαλίδα και στην συνέχεια FS+κωδικός_πεδίου+τιμή πεδίου.

    Δημιουργία & αποστολή μηνύματος
    Πρέπει να το συνθέσουμε την επικεφαλίδα, τα πεδία του και πιθανά τον κωδικό ελέγχου σφάλματος. Γράφουμε το μήνυμα τυφλά σε ένα κανάλι (σειριακό ή TCP/IP) , ελέγχοντας για πιθανά σφάλματα και τα χειριζόμαστε κατάλληλα.

    Παραλαβή και ανάλυση μηνυμάτων.
    Η παραλαβή εξαρτάται από το κανάλι. Σε σειριακή επικοινωνία λαμβάνουμε ένα χαρακτήρα την φορά ενώ στην TCP/IP λαμβάνουμε ολόκληρο το μήνυμα. (character vs block streams).

    Στην πρώτη περίπτωση ένα state machine μας καθοδηγεί ώστε ανάλογα με την κατάσταση (επικεφαλίδα, πεδία, checksum) να ελέγχουμε την λήψη (και τα timeouts).
    Στο state machine ελέγχουμε την δομή του μηνύματος. Ο ακριβής έλεγχος του περιεχομένου (τύπος και δομή κάθε πεδίου) έπεται.

    Στη περίπτωση της TCP/IP επικοινωνίας πιθανά δεν έχουμε checksum (το ίδιο το TCP/IP εγγυάται την ορθότητα του μηνύματος). Δεν απαιτείται state machine κατά την λήψη και προχωράμε απευθείας στον έλεγχο του περιεχομένου

    Έλεγχος τύπου και δομής κάθε πεδίου
    1. Μπορούμε σε ένα τεράστιο case να ελένξουμε κάθε ένα πεδίο (Chuck Norris way).
    2. Υπάρχει, η στατική περιγραφή των πεδίων (schema) και ο έλεγχος ορθότητας κάθε πεδίου με βάση το σχήμα. Έτσι έγραφα σε C και όταν προχώρησα στο Delphi χρησιμοποίησα την ίδια τεχνική. Η συνήθεια είναι 2η φύση. (παρά τον εικονογραφημένο ισχυρισμό μου προς τον dipoli).
    3. Σε προηγούμενο post περιέγραψα το σειριακό πρωτόκολλο ενός φορολογικού εκτυπωτή. Σε αυτό, ο κατασκευαστής όριζε για κάθε πεδίο του μηνύματος επικοινωνίας και τον τύπο του. (Integer, String, Amount, Price, Quantity, Rate, Date8, Time, Flags). Κάθε πεδίο λοιπόν είναι διαφορετικού τύπου και όλα έχουν κοινή την απεικόνιση τους σε ascii.
    Ταιριάζει απόλυτα με την έννοια των domains στις databases.
    Να θυμίσω ότι στο Delphi οι βασικοί τύποι (integer, long, double, string) ΔΕΝ είναι objects και όλα τα objects είναι απόγονοι του TObject.

    Βασικοί τύποι και/ή objects
    Έκανα μάθημα OOP σε ένα πρωτοετή φοιτητή πληροφορικής στο Οικονομικό πανεπιστήμιο. Το ένα θέμα που υπήρξε ήταν ότι επρόκειτο για Java. Και χρειάστηκε να διαβάσω και λίγο ώστε να κατανοώ την σύνταξη της γλώσσας. Το 2ο και σημαντικότερο θέμα που προέκυψε ήταν η Ελληνική ορολογία. (class=τάξη, methods=μηνύματα κτλ)
    Όμως οι δυνατότητες της Java οδηγούν σε διαφορετικό, απόλυτα αντικειμενοστρεφή, τρόπο υλοποίησης. Η Delphi είναι απόγονος της Turbo pascal και έπρεπε να διατηρήσει όλες τις δυνατότητες του προγόνου (συμβατότητα προς τα πίσω ή κληρονομικότητα είναι τελικά το ίδιο πράγμα)

    Όλοι οι τύποι είναι objects και κληρονομούν από ένα βασικό πατέρα το οbject.

    Πως καταλήγουμε λοιπόν.

    Κώδικας:
    type TObjClass = class of TObj;
    
         TObj = class
           protected
            procedure fromAscii(const a:string); virtual;
            function  toAscii:string; virtual;
            procedure nag;
           public
            function  equals(a:TObj):boolean; virtual;// same instance
            property  Ascii:string read toAscii write fromAscii;
         end;
    
         TString = class(TObj)
           private
            Fs:string;
           public
            constructor Create(const a:string);
            procedure fromAscii(const a:string); override;
            function  toAscii:string; override;
            function  equals(a:TObj):boolean; override;
           end;
    
         TA = class(TString) // alpha
           protected
            procedure fromAscii(const a:string); override;
         end;
    
         TAN  = class(TString) // alphanumeric
           protected
            procedure fromAscii(const a:string); override;
         end;
    
         TNumber = class(TObj)
           private
            Ftype: integer;
    // και απλές μεταβλητές θα αρκούσαν ... :)
            FNum : record case integer of
                     0 : (b  : byte);
                     1 : (w  : word);
                     2 : (sh : shortInt);
                     3 : (sm : smallInt);
                     4 : (i  : integer);
                     5 : (c  : cardinal);
                     6 : (i64: int64);
                    end;
           public
            constructor Create(const b:byte); overload;
            constructor Create(const w:word); overload;
            constructor Create(const i:ShortInt); overload;
            constructor Create(const i:SmallInt); overload;
            constructor Create(const i:integer); overload;
            constructor Create(const c:cardinal); overload;
            constructor Create(const i:int64); overload;
            function equals(a:TObj):boolean; override;// same instance
           end;
    …
    
    { TObj }
    
    function TObj.equals(a: TObj): boolean;
     begin
      result:=self=a;
     end;
    
    procedure TObj.fromAscii(const a: string);
     begin
     end;
    
    procedure TObj.nag;
     begin
      raise Exception.CreateFmt('Invalid ascii for type %s',[ClassName]);
     end;
    
    function TObj.toAscii: string;
     begin
      result:='';
     end;
    
    { TString }
    
    constructor TString.Create(const a: string);
     begin
      Fs:=a;
     end;
    
    function TString.equals(a: TObj): boolean;
     begin
      result:=(a is ClassType) and (TString(a).Fs=Fs);
     end;
    
    procedure TString.fromAscii(const a: string);
     begin
      fs:=a;
     end;
    
    function TString.toAscii: string;
     begin
      result:=fs;
     end;
    
    { TNumber }
    
    constructor TNumber.Create(const w: word);
     begin
      FType   := 1;
      FNum.w  := w;
     end;
    
    constructor TNumber.Create(const b: byte);
     begin
      FType   := 0;
      FNum.b  := b;
     end;
    …
    function TNumber.equals(a: TObj): boolean;
     begin
      result:=(a is ClassType);
      if result then
       case Ftype of
        0 : result :=  FNum.b=TNumber(a).FNum.b;
        1 : result :=  FNum.w=TNumber(a).FNum.w;
        2 : result :=  FNum.sh=TNumber(a).FNum.sh;
        3 : result :=  FNum.sm=TNumber(a).FNum.sm;
        4 : result :=  FNum.i=TNumber(a).FNum.i;
        5 : result :=  FNum.c=TNumber(a).FNum.c;
        6 : result :=  FNum.i64=TNumber(a).FNum.i64;
       else
        result:=false;
       end;
     end;
    
    { TA }
    
    procedure TA.fromAscii(const a: string);
     var i:integer;
     begin
      for i:=1 to length(a) do
       if not (a[i] in ['A'..'Z','a'..'z']) then nag;
      fs:=a;
     end;
    
    
    { TAN }
    
    procedure TAN.fromAscii(const a: string);
     var i:integer;
     begin
      for i:=1 to length(a) do
       if not (a[i] in ['0'..'9','A'..'Z','a'..'z']) then nag;
      fs:=a;
     end;
    Δηλώνουμε ένα πίνακα από Ν ΤObjs.

    Κώδικας:
    var Fields : array[0..3] of TObj;
    Δηλώνουμε την κλάση κάθε στοιχείου του πίνακα

    Κώδικας:
    const FieldTypes : array[0..3] of TObjClass =
                       ( TString,
                         TNumber,
                         TA,
                         TAN
                       );
    Σε κάθε θέση του πίνακα αναθέτουμε ένα αντικείμενο της κατάλληλης κλάσης.

    Κώδικας:
      for i:=low(Fields) to High(Fields) do
       Fields[i]:=FieldTypes[i].Create;
    Ο πολυμορφισμός εν δράσει.
    Κώδικας:
      Fields[0].Ascii:='Panos';
      Fields[1].Ascii:='12345';
      Fields[2].Ascii:='12345'; // invalid assignment, nag is called
      Fields[3].Ascii:='12345';
    Συνεχίζεται…

  5. #5
    Μέλος
    Ημερομηνία εγγραφής
    Mar 2012
    Θέση
    Athens, , Greece.
    Ιδιότητα:
    Αγνωστη
    Απαντήσεις
    99
    Πήρα τηλέφωνο στο Γρηγόρη για κάτι άσχετο. Και με ρώτησε γιατί έχω τόσο καιρό να γράψω στο Site. Έκανα κάποιους γρήγορους υπολογισμούς και κατέληξα στο συμπέρασμα ότι οι αναγνώστες μου μπορεί, μαζί με τον Γρηγόρη να πλησιάζουν τους 6.

    Τρομακτική επιτυχία. Οπλισμένος λοιπόν με τον ενθουσιασμό της συγγραφικής επιτυχίας συνεχίζω στο γνωστικό μου αντικείμενο, το software. (Ίσως στο μέλλον όταν αρχίσω να αναγνωρίζω και τα εξαεριστικά να συνδράμω και αλλού[8D]).

    Έλεγχος ορθότητας πεδίων ενός μηνύματος.

    Ένα μήνυμα αποτελείται από συγκεκριμένο ή μεταβλητό αριθμό πεδίων. Τα πεδία μπορεί να είναι προκαθορισμένου μήκους ή να χωρίζονται μεταξύ τους με field separators (διαχωριστές πεδίων) ή το μήκος τους πεδίου να είναι οι 2ή 3 πρώτοι χαρακτήρες.

    Μόλις λάβουμε ένα μήνυμα το ελέγχουμε για την ορθότητά του και στη συνέχεια το «σπάμε» στα πεδία που το συνθέτουν.

    Κάθε πεδίο ανήκει σε ένα τύπο ή domain. Το domain είναι υψηλοτέρου επιπέδου έννοια. Το double είναι τύπος αλλά το Quantity, Price, Amount είναι domains με βασικό τύπο το double και επιπλέον ιδιότητες (μονάδες, όρια τιμών). Αν τα πεδία είναι σε ascii μορφή τότε χρησιμοποιούμε ένα TStringList για να τα αποθηκεύουμε. Εναλλακτικά μπορούμε να χρησιμοποιήσουμε ένα array από TObjs ή (επηρεασμένοι από την VB και το scripting) ένα array of variants.

    Τα variants σαν data type είναι ακριβή λύση από άποψη μεγέθους και ταχύτητας κώδικα.

    Είτε με procedural τρόπο είτε με OOP στο τέλος πρέπει να ελένξουμε αν η τιμή που πρόκειται να αναθέσουμε σε ένα πεδίο είναι επιτρεπτή. Αυτό γίνεται με κατάλληλη ρουτίνα

    Κώδικας:
        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;
    ή με την χρήση regular expressions.

    Regular Expressions

    Είναι μια σειρά από κανόνες (γραμματική δηλαδή) με τους οποίους περιγράφουμε αλληλουχίες χαρακτήρων.

    Κώδικας:
    \n: ταιριάζει με την νέα γραμμή 0x0a
    \r: ταιριάζει με την αλλαγή γραμμή 0x0d
    \d: ταιριάζει με ψηφίο
    . : ταιριάζει με οποιοδήποτα χαρακτήρα εκτός του \n
    \:  πριν από χαρακτήρα ισοδυναμεί με τον χαρακτήρα.
     
    ^ : ταιριάζει με την αρχή ενός string
    $ : ταιριάζει με το τέλος ενός string
    
    ? : ταιριάζει με το προηγούμενο στοιχείο καμία ή μία φορά (0,1)
    * : ταιριάζει με το προηγούμενο στοιχείο καμία ή περισσότερες φορές (0,πολλές)
    + : ταιριάζει με το προηγούμενο στοιχείο μία ή περισσότερες φορές (1,πολλές)
    {n}: ταιριάζει με το προηγούμενο στοιχείο n φορές
    
    (..) : υποέκφραση, αρίθμηση από το 0
    [..] : ομάδα χαρακτήρων που ταιριάζει μόνο με ένα χαρακτήρα
    [^..]: not το παραπάνω
    Αριθμός τηλεφώνου : \d{10}
    Ένας πραγματικός αριθμός με έως 2 δεκαδικά : ^[\+|\-]?(\d*\.?\d{0,2})$

    Εκπτωτικά κουπόνια 981-982 : 98[1|2]\d{10}

    Έλεχγος για το τύπο πιστωτικής κάρτας
    Visa (length 16, prefix 4),
    Mastercard (length 16, prefix 51-55),
    Discover (length 16, prefix 6011),
    American Express (length 15, prefix 34 or 37).
    Κώδικας:
    ^((4\d{3})|(5[1-5]\d{2})|(6011))-?\d{4}-?\d{4}-?\d{4}|3[4,7]\d{13}$
    Έλεγχος κανόνων για ισχυρά passwords

    1 Case Sensitive
    2 Να περιέχουν τουλάχιστον έναν αριθμητικό και έναν αλφαβητικό χαρακτήρα.
    3 Να είναι τουλάχιστον μήκους 6 αλφαριθμητικών χαρακτήρων (και μέγιστο 10)
    4 Να επιτρέπονται σημεία στίξης(!@#$%^&*()_+|~=\‘{}[]:";’<>?,./).
    5 Ο πρώτος και το τελευταίος χαρακτήρας του να μην είναι αριθμός.
    Κώδικας:
    ^[\D](?=.+\d)[\w!@#$%^&*()_+|~={}]{4,8}[\D]$
    Θυμηθείτε. Όταν θέλετε να ψάξετε για κάτι σύνθετο ή να ελένξετε μια καταχώρηση για ορθότητα χρησιμοποιείστε regular expressions.



    Επίλογος
    Οι χρεωστικές κάρτες απαιτούν να υπάρχει το προς ανάληψη – πληρωμή ποσό στον λογαριασμό μας.
    Οι πιστωτικές κάρτες παρέχουν πίστωση και είναι σημαντικό εργαλείο εφόσον πληρώνονται στην ώρα τους σε όλο το ποσό και όχι την ελάχιστη δοση.
    Το μεγαλύτερο ποσοστό απάτης με πιστωτικές κάρτες γίνεται από τα στοιχεία που τηρούν οι έμποροι. Πλέον οι τράπεζες απαιτούν την συμμόρφωση των μηχανογραφικών συστημάτων των εμπόρων με τον PCI DSS κανονισμό.
    Οι κάρτες με chip ΔΕΝ πρέπει να χρησιμοποιούνται σαν μαγνητικές.
    Δεν επιτρέπεται συναλλαγή με χρεωστική κάρτα χωρίς PIN.

    Και φυσικά ΜΗΝ γράφετε τα PIN πάνω στις κάρτες σας.
    ΜΗΝ χρησιμοποιήστε το έτος γέννησης σας ή το 1234 σαν PIN.
    Βρέστε κάτι λιγότερο προφανές.

    Και για αγορές από το internet προτείνω ΜΟΝΟ prepaid κάρτα "γεμάτη" μόνο με το ποσό της αγοράς.

    Σχόλια/διορθώσεις και ερωτήσεις δεκτές.

    ΠΦ
    Mature software developer.

  6. #6
    Εξέχον μέλος
    Ημερομηνία εγγραφής
    Oct 2010
    Θέση
    Athens, , Greece.
    Ιδιότητα:
    Αγνωστη
    Απαντήσεις
    1,632
    Η μονη "διαφωνια μου" ειναι για τις prepaid.

    Ειναι καλες μονο για τις τραπεζες γιατι αποφερουν κερδος... (και για πιτσιρικαδες, γενικοτερα για unbanked καταστασεις..)
    Για τον απλο χρηστη εχουν τους ιδιους κινδυνους οποως και οι κανονικες.

    (οποοιος διαφωνει να μου δωσει την prepaid του με 100 ευρω μεσα και να περιμενει τηλεφωνο απο την τραπεζα του οτι χρωσταει... )

    Για οποιον παρολα αυτα φοβαται, ας φτιαξει ενα δωρεαν λογαριασμο συνδεδεμενο με debit και να βαζει εκει το ποσο που θελει να ξοδεψει με web-banking.
    Μηδενικο κοστος εκδοσης, μηδενικο κοστος χρησης..


    Burn baby, burn

  7. #7
    Επίλεκτο μέλος
    Ημερομηνία εγγραφής
    Mar 2011
    Θέση
    ΧΑΝΙΑ, , Greece.
    Ιδιότητα:
    Απαντήσεις
    163
    quoteοποοιος διαφωνει να μου δωσει την prepaid του με 100 ευρω μεσα και να περιμενει τηλεφωνο απο την τραπεζα του οτι χρωσταει... )
    Δηλαδή Σωτήρη εννοείς ότι ενώ έχω μέσα 100 ευρώ μπορεί κάποιος να με χρεώσει με 200 ευρώ και να με ειδοποιήσει η τράπεζα μου ότι χρωστάω και άλλα 100 ευρώ ;

    quote:Για οποιον παρολα αυτα φοβαται, ας φτιαξει ενα δωρεαν λογαριασμο συνδεδεμενο με debit και να βαζει εκει το ποσο που θελει να ξοδεψει με web-banking.
    Μηδενικο κοστος εκδοσης, μηδενικο κοστος χρησης..
    Για ανάλυσε το αυτό περισσότερο μπας και καταλάβουμε τίποτα…. Εσύ πώς αγοράζεις από το ιντερνέτ με ασφάλεια ;

  8. #8
    Εξέχον μέλος
    Ημερομηνία εγγραφής
    Oct 2010
    Θέση
    Athens, , Greece.
    Ιδιότητα:
    Αγνωστη
    Απαντήσεις
    1,632
    Υπαρχουν διαδικασιες που μπρει να γινουν abuse και να βρεθεις να χρωστας παραπανω.

    Και ομως το πιο ασφαλες για αγορες ειναι η κανονικη πιστωτικη, με την προυποθεση οτι την βλεπεις απο το web banking.

    Οτι στραβη και να γινει, ειναι τα λεφτα του πιστωτικου σου οριου (δλδ της τραπεζας).
    Και επειδη η συναλλαγη ειναι τυπου card not present μπορεις να με ευκολια να αρνηθεις τα παντα.
    Μετα πρεπει να αποδειξει η αλλη πλευρα οτι σου πουλησε...

    Θελω να πω οτι τελικα ο κινδυνος ειναι ιδιος ειτε με prepaid ειτε με χωρις.
    Απλα οι prepaid εχουν φτιαξει ενα κλιμα ψευδους ασφαλειας.
    Ναι ειναι για οποιον δεν ασχολειται, για τον ασχετο, για τον unbanked κλπ, αλλα ο λογος που προωθειται ειναι οτι οι τραπεζες ΒΓΑΖΟΥΝ πολυ περισσοτερα
    Αν σκεφτεις οτι περιπου 20% των καρτων ξεχνιεται με ποσο της ταξεως του 15-20% της αρχικης αξιας το οποιο και χανεται μετα απο καποιους μηνες, μια χαρα μπιζνα ειναι.


    Burn baby, burn

  9. #9
    Εξέχον μέλος
    Ημερομηνία εγγραφής
    Jul 2007
    Θέση
    Athens
    Ιδιότητα:
    Αγνωστη
    Απαντήσεις
    4,177
    quote:Πήρα τηλέφωνο στο Γρηγόρη για κάτι άσχετο. Και με ρώτησε γιατί έχω τόσο καιρό να γράψω στο Site. Έκανα κάποιους γρήγορους υπολογισμούς και κατέληξα στο συμπέρασμα ότι οι αναγνώστες μου μπορεί, μαζί με τον Γρηγόρη να πλησιάζουν τους 6.
    Πέρα που σε εκτιμώ και σε γουστάρω βρήκες και εσύ να γράψεις για τις τράπεζες...
    Ο έρμος ο Γρηγόρης.... όσο λαϊκίστικο να φαίνεται αυτό σε μερικούς...με τις τράπεζες είναι εχθροί....
    Το ξέρεις και το ξέρω...

    http://udravlikos.gr

  10. #10
    Μέλος
    Ημερομηνία εγγραφής
    Mar 2012
    Θέση
    Athens, , Greece.
    Ιδιότητα:
    Αγνωστη
    Απαντήσεις
    99

    Ηλεκτρονικό κατάστημα ειδών θέρμανσης και κλιματισμού

    Γειά σου ρε μάστορα με τους οχτρούς σου. Σε έχασα το ομολογώ.
    Εσύ απλά με παρακίνησες να συνεχίσω το thread.

    Έγραψα για ένα πρωτόκολλο με συγχρονισμό των 2 άκρων.
    Περιέγραψα τον μεταβλητό αριθμός πεδίο με bitmap ή διαχωριστικά πεδίων.
    Μίλησα για types & domains και υλοποίηση τους με πολυμορφισμό
    κτλ
    κτλ

    Με πλήγωσες. Με έριξες πολύ χαμηλά και χρειάζομαι απαραίτητα γερή δόση κοψιδίων με το απαραίτητο οίνο για να συνέλθω. Ίσως και λίγο ρακί να βοηθούσε.

    Αλλά μην ανησυχείς. Υπόσχομαι να συνεχίσω με ποιό ενδιαφέροντα θέματα όπως

    Βάσεις δεδομένων και κλειδιά (indexes).
    Κατανεμημένες εφαρμογές.

    και βλέπουμε...


Δικαιώματα απάντησης

  • You may not post new threads
  • ΔΕΝ έχετε το δικαίωμα απάντησης
  • You may not post attachments
  • ΔΕΝ μπορείτε να επεξεργαστειτε τις απαντησεις σας
  •  
  • BB code is Ανοικτό
  • Smilies are Ανοικτό
  • [IMG] code is Ανοικτό
  • [VIDEO] code is Κλειστό
  • HTML code is Κλειστό