<?php

/*
 * This file is part of the Jejik\MT940 library
 *
 * Copyright (c) 2012 Sander Marechal <s.marechal@jejik.com>
 * Licensed under the MIT license
 *
 * For the full copyright and license information, please see the LICENSE
 * file that was distributed with this source code.
 */

namespace Jejik\MT940\Parser;

use Jejik\MT940\Balance;
use Jejik\MT940\AccountInterface;
use Jejik\MT940\BalanceInterface;
use Jejik\MT940\StatementInterface;
use Jejik\MT940\Reader;
use Jejik\MT940\Statement;
use Jejik\MT940\Transaction;

/**
 * Base MT940 parser
 *
 * @author Sander Marechal <s.marechal@jejik.com>
 */
abstract class AbstractParser
{
    // Properties {{{

    /**
     * Reference to the MT940 reader
     *
     * @var Reader
     */
    protected $reader;

    // }}}

    /**
     * Constructor
     *
     * @param Reader $reader Reference to the MT940 reader
     */
    public function __construct(Reader $reader)
    {
        $this->reader = $reader;
    }

    /**
     * Parse an MT940 document
     *
     * @param string $text Full document text
     * @return array An array of \Jejik\MT940\Statement
     */
    public function parse($text)
    {
        $statements = array();
        foreach ($this->splitStatements($text) as $chunk) {
            if ($statement = $this->statement($chunk)) {
                $statements[] = $statement;
            }
        }

        return $statements;
    }

    /**
     * Get the contents of an MT940 line
     *
     * The contents may be several lines long (e.g. :86: descriptions)
     *
     * @param string $id The line ID (e.g. "20"). Can be a regular expression (e.g. "60F|60M")
     * @param string $text The text to search
     * @param int $offset The offset to start looking
     * @param int $position Starting position of the found line
     * @param int $length Length of the found line (before trimming), including EOL
     * @return string
     */
    protected function getLine($id, $text, $offset = 0, &$position = null, &$length = null)
    {
        $pcre = '/(?:^|\r?\n)\:(' . $id . ')\:'   // ":<id>:" at the start of a line
              . '(.+)'                           // Contents of the line
              . '(:?$|\r?\n\:[[:alnum:]]{2,3}\:)' // End of the text or next ":<id>:"
              . '/Us';                           // Ungreedy matching

        // Offset manually, so the start of the offset can match ^
        if (preg_match($pcre, substr($text, $offset), $match, PREG_OFFSET_CAPTURE)) {
            $position = $offset + $match[1][1] - 1;
            $length = strlen($match[2][0]);
            return rtrim($match[2][0]);
        }

        return '';
    }

    /**
     * Split the text into separate statement chunks
     *
     * @param string $text Full document text
     * @return array Array of statement texts
     * @throws \RuntimeException if the statementDelimiter is not set
     */
    protected function splitStatements($text)
    {
        $chunks = preg_split('/^:20:/m', $text, -1);
        $chunks = array_filter(array_map('trim', array_slice($chunks, 1)));

        // Re-add the :20: at the beginning
        return array_map(function ($statement) {
            return ':20:' . $statement;
        }, $chunks);
    }

    /**
     * Split transactions and their descriptions from the statement text
     *
     * Returns a nexted array of transaction lines. The transaction line text
     * is at offset 0 and the description line text (if any) at offset 1.
     *
     * @param string $text Statement text
     * @return array Nested array of transaction and description lines
     */
    protected function splitTransactions($text)
    {
        $offset = 0;
        $length = 0;
        $position = 0;
        $transactions = array();

        while ($line = $this->getLine('61', $text, $offset, $offset, $length)) {
            $offset += 4 + $length + 2;
            $transaction = array($line);

            // See if the next description line belongs to this transaction line.
            // The description line should immediately follow the transaction line.
            $description = array();
            while ($line = $this->getLine('86', $text, $offset, $position, $length)) {
                if ($position == $offset) {
                    $offset += 4 + $length + 2;
                    $description[] = $line;
                } else {
                    break;
                }
            }

            if ($description) {
                $transaction[] = implode("\r\n", $description);
            }

            $transactions[] = $transaction;
        }

        return $transactions;
    }

    /**
     * Parse a statement chunk
     *
     * @param string $text Statement text
     * @return \Jejik\MT940\Statement
     * @throws \RuntimeException if the chunk cannot be parsed
     */
    protected function statement($text)
    {
        $text = trim($text);
        if (($pos = strpos($text, ':20:')) === false) {
            throw new \RuntimeException('Not an MT940 statement');
        }

        $this->statementHeader(substr($text, 0, $pos));
        return $this->statementBody(substr($text, $pos));
    }

    /**
     * Parse a statement header
     *
     * @param string $text Statement header text
     * @return void
     */
    protected function statementHeader($text)
    {
    }

    /**
     * Parse a statement body
     *
     * @param string $text Statement body text
     * @return \Jejik\MT940\Statement
     */
    protected function statementBody($text)
    {
        $accountNumber = $this->accountNumber($text);
        $account = $this->reader->createAccount($accountNumber);

        if (!($account instanceof AccountInterface)) {
            return null;
        }

        $account->setNumber($accountNumber);
        $number = $this->statementNumber($text);
        $statement = $this->reader->createStatement($account, $number);

        if (!($statement instanceof StatementInterface)) {
            return null;
        }

        $statement->setAccount($account)
                  ->setNumber($this->statementNumber($text))
                  ->setOpeningBalance($this->openingBalance($text))
                  ->setClosingBalance($this->closingBalance($text));

        foreach ($this->splitTransactions($text) as $chunk) {
            $statement->addTransaction($this->transaction($chunk));
        }

        return $statement;
    }

    /**
     * Parse a statement number
     *
     * @param string $text Statement body text
     * @return string|null
     */
    protected function statementNumber($text)
    {
        if ($number = $this->getLine('28|28C', $text)) {
            return $number;
        }

        return null;
    }

    /**
     * Parse an account number
     *
     * @param string $text Statement body text
     * @return string|null
     */
    protected function accountNumber($text)
    {
        if ($account = $this->getLine('25', $text)) {
            return ltrim($account, '0');
        }

        return null;
    }

    /**
     * Fill a Balance object from an MT940  balance line
     *
     * @param BalanceInterface $balance
     * @param string $text
     * @return \Jejik\MT940\Balance
     */
    protected function balance(BalanceInterface $balance, $text)
    {
        if (!preg_match('/(C|D)(\d{6})([A-Z]{3})([0-9,]{1,15})/', $text, $match)) {
            throw new \RuntimeException(sprintf('Cannot parse balance: "%s"', $text));
        }

        $amount = (float) str_replace(',', '.', $match[4]);
        if ($match[1] === 'D') {
            $amount *= -1;
        }

        $date = \DateTime::createFromFormat('ymd', $match[2]);
        $date->setTime(0, 0, 0);

        $balance->setCurrency($match[3])
                ->setAmount($amount)
                ->setDate($date);

        return $balance;
    }

    /**
     * Get the opening balance
     *
     * @param mixed $text
     * @return \Jejik\MT940\Balance
     */
    protected function openingBalance($text)
    {
        if ($line = $this->getLine('60F|60M', $text)) {
            return $this->balance($this->reader->createOpeningBalance(), $line);
        }
    }

    /**
     * Get the closing balance
     *
     * @param mixed $text
     * @return \Jejik\MT940\Balance
     */
    protected function closingBalance($text)
    {
        if ($line = $this->getLine('62F|62M', $text)) {
            return $this->balance($this->reader->createClosingBalance(), $line);
        }
    }

    /**
     * Create a Transaction from MT940 transaction text lines
     *
     * @param array $lines The transaction text at offset 0 and the description at offset 1
     * @return \Jejik\MT940\Transaction
     */
    protected function transaction(array $lines)
    {
        if (!preg_match('/(\d{6})((\d{2})(\d{2}))?(C|D)([A-Z]?)([0-9,]{1,15})/', $lines[0], $match)) {
            throw new \RuntimeException(sprintf('Could not parse transaction line "%s"', $lines[0]));
        }

        // Parse the amount
        $amount = (float) str_replace(',', '.', $match[7]);
        if ($match[5] === 'D') {
            $amount *= -1;
        }

        // Parse dates
        $valueDate = \DateTime::createFromFormat('ymd', $match[1]);
        $valueDate->setTime(0, 0, 0);

        $bookDate = null;

        if ($match[2]) {
            // Construct book date from the month and day provided by adding the year of the value date as best guess.
            $month = intval($match[3]);
            $day = intval($match[4]);
            $bookDate = $this->getNearestDateTimeFromDayAndMonth($valueDate, $day, $month);
        }

        $description = isset($lines[1]) ? $lines[1] : null;
        $transaction = $this->reader->createTransaction();
        $transaction->setAmount($amount)
                    ->setContraAccount($this->contraAccount($lines))
                    ->setValueDate($valueDate)
                    ->setBookDate($bookDate)
                    ->setDescription($this->description($description));

        return $transaction;
    }

    /**
     * Finds the closest \DateTime to the given target \DateTime with the set day and month.
     * Will try at most 3 \Datetime's, one a year before our initial guess, and one a year after.
     * Returns the one with the least days difference in days.
     *
     * @param \DateTime $target
     * @param int $day
     * @param int $month
     * @return \DateTime
     */
    protected function getNearestDateTimeFromDayAndMonth(\DateTime $target, $day, $month)
    {
        $initialGuess = new \DateTime();
        $initialGuess->setDate($target->format('Y'), $month, $day);
        $initialGuess->setTime(0, 0, 0);
        $initialGuessDiff = $target->diff($initialGuess);

        $yearEarlier = clone $initialGuess;
        $yearEarlier->modify('-1 year');
        $yearEarlierDiff = $target->diff($yearEarlier);

        if ($yearEarlierDiff->days < $initialGuessDiff->days) {
            return $yearEarlier;
        }

        $yearLater = clone $initialGuess;
        $yearLater->modify('+1 year');
        $yearLaterDiff = $target->diff($yearLater);

        if ($yearLaterDiff->days < $initialGuessDiff->days) {
            return $yearLater;
        }

        return $initialGuess;
    }

    /**
     * Get the contra account from a transaction
     *
     * @param array $lines The transaction text at offset 0 and the description at offset 1
     * @return \Jejik\MT940\AccountInterface|null
     */
    protected function contraAccount(array $lines)
    {
        $number = $this->contraAccountNumber($lines);
        $name = $this->contraAccountName($lines);

        if ($name || $number) {
            $contraAccount = $this->reader->createContraAccount($number);
            $contraAccount->setNumber($number)
                          ->setName($name);

            return $contraAccount;
        }

        return null;
    }

    /**
     * Get the contra account number from a transaction
     *
     * @param array $lines The transaction text at offset 0 and the description at offset 1
     * @return string|null
     */
    protected function contraAccountNumber(array $lines)
    {
        return null;
    }

    /**
     * Get the contra account holder name from a transaction
     *
     * @param array $lines The transaction text at offset 0 and the description at offset 1
     * @return string|null
     */
    protected function contraAccountName(array $lines)
    {
        return null;
    }

    /**
     * Process the description
     *
     * @param string $description
     * @return string
     */
    protected function description($description)
    {
        return $description;
    }

    /**
     * Test if the document can be read by the parser
     *
     * @param string $text
     * @return bool
     */
    abstract public function accept($text);
}


<?php

/*
 * This file is part of the Jejik\MT940 library
 *
 * Copyright (c) 2012 Sander Marechal <s.marechal@jejik.com>
 * Licensed under the MIT license
 *
 * For the full copyright and license information, please see the LICENSE
 * file that was distributed with this source code.
 */

namespace Jejik\MT940\Parser;

/**
 * Parser for PostFinance documents
 *
 * @author Sander Marechal <s.marechal@jejik.com>
 */
class PostFinance extends AbstractParser
{
    /**
     * Test if the document is an ABN-AMRO document
     *
     * @param string $text
     * @return bool
     */
    public function accept($text)
    {
        return strpos(strtok($text, "\n"), 'POFICH') !== false;
    }

    /**
     * Get the closing balance
     *
     * @param mixed $text
     * @return void
     */
    protected function closingBalance($text)
    {
        if ($line = $this->getLine('62M', $text)) {
            return $this->balance($this->reader->createClosingBalance(), $line);
        }
    }

    /**
     * Get the contra account number from a transaction
     *
     * @param array $lines The transaction text at offset 0 and the description at offset 1
     * @return string|null
     */
    protected function contraAccountNumber(array $lines)
    {
        if (!preg_match('/\n(\d{8})\d{7}(\d{8})/', $lines[0], $match)) {
            return null;
        }

        $date = substr($match[1], 2);
        $number = $match[2];

        if (preg_match(sprintf('/%sCH%s/', $date, $number), $lines[1])) {
            return $number;
        }

        return null;
    }
}


<?php
/**
 * CreateChargeRequest
 *
 * @category Class
 * @package  zipMoney
 * @author   zipMoney Payments Pty Ltd
 * @link     https://github.com/zipMoney/merchantapi-php
 */

namespace zipMoney\Model;

use \ArrayAccess;

class CreateChargeRequest implements ArrayAccess
{
    const DISCRIMINATOR = 'subclass';

    /**
      * The original name of the model.
      * @var string
      */
    protected static $swaggerModelName = 'CreateChargeRequest';

    /**
      * Array of property to type mappings. Used for (de)serialization
      * @var string[]
      */
    protected static $zipTypes = array(
        'authority' => '\zipMoney\Model\Authority',
        'reference' => 'string',
        'amount' => 'float',
        'currency' => 'string',
        'capture' => 'bool',
        'order' => '\zipMoney\Model\ChargeOrder',
        'metadata' => 'object'
    );

    public static function zipTypes()
    {
        return self::$zipTypes;
    }

    /**
     * Array of attributes where the key is the local name, and the value is the original name
     * @var string[]
     */
    protected static $attributeMap = array(
        'authority' => 'authority',
        'reference' => 'reference',
        'amount' => 'amount',
        'currency' => 'currency',
        'capture' => 'capture',
        'order' => 'order',
        'metadata' => 'metadata'
    );

    /**
     * Array of attributes to setter functions (for deserialization of responses)
     * @var string[]
     */
    protected static $setters = array(
        'authority' => 'setAuthority',
        'reference' => 'setReference',
        'amount' => 'setAmount',
        'currency' => 'setCurrency',
        'capture' => 'setCapture',
        'order' => 'setOrder',
        'metadata' => 'setMetadata'
    );

    /**
     * Array of attributes to getter functions (for serialization of requests)
     * @var string[]
     */
    protected static $getters = array(
        'authority' => 'getAuthority',
        'reference' => 'getReference',
        'amount' => 'getAmount',
        'currency' => 'getCurrency',
        'capture' => 'getCapture',
        'order' => 'getOrder',
        'metadata' => 'getMetadata'
    );

    public static function attributeMap()
    {
        return self::$attributeMap;
    }

    public static function setters()
    {
        return self::$setters;
    }

    public static function getters()
    {
        return self::$getters;
    }

    const CURRENCY_AUD = 'AUD';
    const CURRENCY_NZD = 'NZD';

    /**
     * Gets allowable values of the enum
     * @return string[]
     */
    public function getCurrencyAllowableValues()
    {
        return array(
            self::CURRENCY_AUD,
            self::CURRENCY_NZD,
        );
    }

    /**
     * Associative array for storing property values
     * @var mixed[]
     */
    protected $container = array();

    /**
     * Constructor
     * @param mixed[] $data Associated array of property values initializing the model
     */
    public function __construct(array $data = null)
    {
        $this->container['authority'] = isset($data['authority']) ? $data['authority'] : null;
        $this->container['reference'] = isset($data['reference']) ? $data['reference'] : null;
        $this->container['amount'] = isset($data['amount']) ? $data['amount'] : null;
        $this->container['currency'] = isset($data['currency']) ? $data['currency'] : null;
        $this->container['capture'] = isset($data['capture']) ? $data['capture'] : true;
        $this->container['order'] = isset($data['order']) ? $data['order'] : null;
        $this->container['metadata'] = isset($data['metadata']) ? $data['metadata'] : null;
    }

    /**
     * show all the invalid properties with reasons.
     *
     * @return array invalid properties with reasons
     */
    public function listInvalidProperties()
    {
        $invalid_properties = array();

        if ($this->container['authority'] === null) {
            $invalid_properties[] = "'authority' can't be null";
        }
        if ($this->container['amount'] === null) {
            $invalid_properties[] = "'amount' can't be null";
        }
        if ($this->container['currency'] === null) {
            $invalid_properties[] = "'currency' can't be null";
        }
        $allowed_values = array("AUD", "NZD");
        if (!in_array($this->container['currency'], $allowed_values)) {
            $invalid_properties[] = "invalid value for 'currency', must be one of 'AUD', 'NZD'.";
        }

        return $invalid_properties;
    }

    /**
     * validate all the properties in the model
     * return true if all passed
     *
     * @return bool True if all properties are valid
     */
    public function valid()
    {

        if ($this->container['authority'] === null) {
            return false;
        }
        if ($this->container['amount'] === null) {
            return false;
        }
        if ($this->container['currency'] === null) {
            return false;
        }
        $allowed_values = array("AUD", "NZD");
        if (!in_array($this->container['currency'], $allowed_values)) {
            return false;
        }
        return true;
    }

    /**
     * Gets authority
     * @return \zipMoney\Model\Authority
     */
    public function getAuthority()
    {
        return $this->container['authority'];
    }

    /**
     * Sets authority
     * @param \zipMoney\Model\Authority $authority
     * @return $this
     */
    public function setAuthority($authority)
    {
        $this->container['authority'] = $authority;

        return $this;
    }

    /**
     * Gets reference
     * @return string
     */
    public function getReference()
    {
        return $this->container['reference'];
    }

    /**
     * Sets reference
     * @param string $reference The reference for this charge (unique payment reference in your store)
     * @return $this
     */
    public function setReference($reference)
    {
        $this->container['reference'] = $reference;

        return $this;
    }

    /**
     * Gets amount
     * @return float
     */
    public function getAmount()
    {
        return $this->container['amount'];
    }

    /**
     * Sets amount
     * @param float $amount The amount of the charge
     * @return $this
     */
    public function setAmount($amount)
    {
        $this->container['amount'] = $amount;

        return $this;
    }

    /**
     * Gets currency
     * @return string
     */
    public function getCurrency()
    {
        return $this->container['currency'];
    }

    /**
     * Sets currency
     * @param string $currency The currency
     * @return $this
     */
    public function setCurrency($currency)
    {
        $allowed_values = array('AUD', 'NZD');
        if ((!in_array($currency, $allowed_values))) {
            throw new \InvalidArgumentException("Invalid value for 'currency', must be one of 'AUD', 'NZD'");
        }
        $this->container['currency'] = $currency;

        return $this;
    }

    /**
     * Gets capture
     * @return bool
     */
    public function getCapture()
    {
        return $this->container['capture'];
    }

    /**
     * Sets capture
     * @param bool $capture If true this will be a direct capture, pass false to perform an authorisation only
     * @return $this
     */
    public function setCapture($capture)
    {
        $this->container['capture'] = $capture;

        return $this;
    }

    /**
     * Gets order
     * @return \zipMoney\Model\ChargeOrder
     */
    public function getOrder()
    {
        return $this->container['order'];
    }

    /**
     * Sets order
     * @param \zipMoney\Model\ChargeOrder $order
     * @return $this
     */
    public function setOrder($order)
    {
        $this->container['order'] = $order;

        return $this;
    }

    /**
     * Gets metadata
     * @return object
     */
    public function getMetadata()
    {
        return $this->container['metadata'];
    }

    /**
     * Sets metadata
     * @param object $metadata
     * @return $this
     */
    public function setMetadata($metadata)
    {
        $this->container['metadata'] = $metadata;

        return $this;
    }
    /**
     * Returns true if offset exists. False otherwise.
     * @param  integer $offset Offset
     * @return boolean
     */
    public function offsetExists($offset)
    {
        return isset($this->container[$offset]);
    }

    /**
     * Gets offset.
     * @param  integer $offset Offset
     * @return mixed
     */
    public function offsetGet($offset)
    {
        return isset($this->container[$offset]) ? $this->container[$offset] : null;
    }

    /**
     * Sets value based on offset.
     * @param  integer $offset Offset
     * @param  mixed   $value  Value to be set
     * @return void
     */
    public function offsetSet($offset, $value)
    {
        if (is_null($offset)) {
            $this->container[] = $value;
        } else {
            $this->container[$offset] = $value;
        }
    }

    /**
     * Unsets offset.
     * @param  integer $offset Offset
     * @return void
     */
    public function offsetUnset($offset)
    {
        unset($this->container[$offset]);
    }

    /**
     * Gets the string presentation of the object
     * @return string
     */
    public function __toString()
    {
        if (defined('JSON_PRETTY_PRINT')) { // use JSON pretty print
            return json_encode(\zipMoney\ObjectSerializer::sanitizeForSerialization($this), JSON_PRETTY_PRINT);
        }

        return json_encode(\zipMoney\ObjectSerializer::sanitizeForSerialization($this));
    }
}


<?php
/**
 * Token
 *
 * @category Class
 * @package  zipMoney
 * @author   zipMoney Payments Pty Ltd
 * @link     https://github.com/zipMoney/merchantapi-php
 */

namespace zipMoney\Model;

use \ArrayAccess;

class Token implements ArrayAccess
{
    const DISCRIMINATOR = 'subclass';

    /**
      * The original name of the model.
      * @var string
      */
    protected static $swaggerModelName = 'token';

    /**
      * Array of property to type mappings. Used for (de)serialization
      * @var string[]
      */
    protected static $zipTypes = array(
        'id' => 'string',
        'value' => 'string',
        'active' => 'bool',
        'created_date' => '\DateTime'
    );

    public static function zipTypes()
    {
        return self::$zipTypes;
    }

    /**
     * Array of attributes where the key is the local name, and the value is the original name
     * @var string[]
     */
    protected static $attributeMap = array(
        'id' => 'id',
        'value' => 'value',
        'active' => 'active',
        'created_date' => 'created_date'
    );

    /**
     * Array of attributes to setter functions (for deserialization of responses)
     * @var string[]
     */
    protected static $setters = array(
        'id' => 'setId',
        'value' => 'setValue',
        'active' => 'setActive',
        'created_date' => 'setCreatedDate'
    );

    /**
     * Array of attributes to getter functions (for serialization of requests)
     * @var string[]
     */
    protected static $getters = array(
        'id' => 'getId',
        'value' => 'getValue',
        'active' => 'getActive',
        'created_date' => 'getCreatedDate'
    );

    public static function attributeMap()
    {
        return self::$attributeMap;
    }

    public static function setters()
    {
        return self::$setters;
    }

    public static function getters()
    {
        return self::$getters;
    }

    /**
     * Associative array for storing property values
     * @var mixed[]
     */
    protected $container = array();

    /**
     * Constructor
     * @param mixed[] $data Associated array of property values initializing the model
     */
    public function __construct(array $data = null)
    {
        $this->container['id'] = isset($data['id']) ? $data['id'] : null;
        $this->container['value'] = isset($data['value']) ? $data['value'] : null;
        $this->container['active'] = isset($data['active']) ? $data['active'] : null;
        $this->container['created_date'] = isset($data['created_date']) ? $data['created_date'] : null;
    }

    /**
     * show all the invalid properties with reasons.
     *
     * @return array invalid properties with reasons
     */
    public function listInvalidProperties()
    {
        $invalid_properties = array();

        if ($this->container['id'] === null) {
            $invalid_properties[] = "'id' can't be null";
        }
        if ($this->container['value'] === null) {
            $invalid_properties[] = "'value' can't be null";
        }
        if ($this->container['active'] === null) {
            $invalid_properties[] = "'active' can't be null";
        }
        if ($this->container['created_date'] === null) {
            $invalid_properties[] = "'created_date' can't be null";
        }
        return $invalid_properties;
    }

    /**
     * validate all the properties in the model
     * return true if all passed
     *
     * @return bool True if all properties are valid
     */
    public function valid()
    {

        if ($this->container['id'] === null) {
            return false;
        }
        if ($this->container['value'] === null) {
            return false;
        }
        if ($this->container['active'] === null) {
            return false;
        }
        if ($this->container['created_date'] === null) {
            return false;
        }
        return true;
    }

    /**
     * Gets id
     * @return string
     */
    public function getId()
    {
        return $this->container['id'];
    }

    /**
     * Sets id
     * @param string $id
     * @return $this
     */
    public function setId($id)
    {
        $this->container['id'] = $id;

        return $this;
    }

    /**
     * Gets value
     * @return string
     */
    public function getValue()
    {
        return $this->container['value'];
    }

    /**
     * Sets value
     * @param string $value
     * @return $this
     */
    public function setValue($value)
    {
        $this->container['value'] = $value;

        return $this;
    }

    /**
     * Gets active
     * @return bool
     */
    public function getActive()
    {
        return $this->container['active'];
    }

    /**
     * Sets active
     * @param bool $active
     * @return $this
     */
    public function setActive($active)
    {
        $this->container['active'] = $active;

        return $this;
    }

    /**
     * Gets created_date
     * @return \DateTime
     */
    public function getCreatedDate()
    {
        return $this->container['created_date'];
    }

    /**
     * Sets created_date
     * @param \DateTime $created_date
     * @return $this
     */
    public function setCreatedDate($created_date)
    {
        $this->container['created_date'] = $created_date;

        return $this;
    }
    /**
     * Returns true if offset exists. False otherwise.
     * @param  integer $offset Offset
     * @return boolean
     */
    public function offsetExists($offset)
    {
        return isset($this->container[$offset]);
    }

    /**
     * Gets offset.
     * @param  integer $offset Offset
     * @return mixed
     */
    public function offsetGet($offset)
    {
        return isset($this->container[$offset]) ? $this->container[$offset] : null;
    }

    /**
     * Sets value based on offset.
     * @param  integer $offset Offset
     * @param  mixed   $value  Value to be set
     * @return void
     */
    public function offsetSet($offset, $value)
    {
        if (is_null($offset)) {
            $this->container[] = $value;
        } else {
            $this->container[$offset] = $value;
        }
    }

    /**
     * Unsets offset.
     * @param  integer $offset Offset
     * @return void
     */
    public function offsetUnset($offset)
    {
        unset($this->container[$offset]);
    }

    /**
     * Gets the string presentation of the object
     * @return string
     */
    public function __toString()
    {
        if (defined('JSON_PRETTY_PRINT')) { // use JSON pretty print
            return json_encode(\zipMoney\ObjectSerializer::sanitizeForSerialization($this), JSON_PRETTY_PRINT);
        }

        return json_encode(\zipMoney\ObjectSerializer::sanitizeForSerialization($this));
    }
}


<?php
/**
 * ShopperStatistics
 *
 * @category Class
 * @package  zipMoney
 * @author   zipMoney Payments Pty Ltd
 * @link     https://github.com/zipMoney/merchantapi-php
 */

namespace zipMoney\Model;

use \ArrayAccess;

class ShopperStatistics implements ArrayAccess
{
    const DISCRIMINATOR = 'subclass';

    /**
      * The original name of the model.
      * @var string
      */
    protected static $swaggerModelName = 'Shopper_statistics';

    /**
      * Array of property to type mappings. Used for (de)serialization
      * @var string[]
      */
    protected static $zipTypes = array(
        'account_created' => '\DateTime',
        'sales_total_count' => 'int',
        'sales_total_amount' => 'float',
        'sales_avg_amount' => 'float',
        'sales_max_amount' => 'float',
        'refunds_total_amount' => 'float',
        'previous_chargeback' => 'bool',
        'currency' => 'string',
        'last_login' => '\DateTime',
        'has_previous_purchases' => 'bool',
        'fraud_check_result' => 'string'
    );

    public static function zipTypes()
    {
        return self::$zipTypes;
    }

    /**
     * Array of attributes where the key is the local name, and the value is the original name
     * @var string[]
     */
    protected static $attributeMap = array(
        'account_created' => 'account_created',
        'sales_total_count' => 'sales_total_count',
        'sales_total_amount' => 'sales_total_amount',
        'sales_avg_amount' => 'sales_avg_amount',
        'sales_max_amount' => 'sales_max_amount',
        'refunds_total_amount' => 'refunds_total_amount',
        'previous_chargeback' => 'previous_chargeback',
        'currency' => 'currency',
        'last_login' => 'last_login',
        'has_previous_purchases' => 'has_previous_purchases',
        'fraud_check_result' => 'fraud_check_result'
    );

    /**
     * Array of attributes to setter functions (for deserialization of responses)
     * @var string[]
     */
    protected static $setters = array(
        'account_created' => 'setAccountCreated',
        'sales_total_count' => 'setSalesTotalCount',
        'sales_total_amount' => 'setSalesTotalAmount',
        'sales_avg_amount' => 'setSalesAvgAmount',
        'sales_max_amount' => 'setSalesMaxAmount',
        'refunds_total_amount' => 'setRefundsTotalAmount',
        'previous_chargeback' => 'setPreviousChargeback',
        'currency' => 'setCurrency',
        'last_login' => 'setLastLogin',
        'has_previous_purchases' => 'setHasPreviousPurchases',
        'fraud_check_result' => 'setFraudCheckResult'
    );

    /**
     * Array of attributes to getter functions (for serialization of requests)
     * @var string[]
     */
    protected static $getters = array(
        'account_created' => 'getAccountCreated',
        'sales_total_count' => 'getSalesTotalCount',
        'sales_total_amount' => 'getSalesTotalAmount',
        'sales_avg_amount' => 'getSalesAvgAmount',
        'sales_max_amount' => 'getSalesMaxAmount',
        'refunds_total_amount' => 'getRefundsTotalAmount',
        'previous_chargeback' => 'getPreviousChargeback',
        'currency' => 'getCurrency',
        'last_login' => 'getLastLogin',
        'has_previous_purchases' => 'getHasPreviousPurchases',
        'fraud_check_result' => 'getFraudCheckResult'
    );

    public static function attributeMap()
    {
        return self::$attributeMap;
    }

    public static function setters()
    {
        return self::$setters;
    }

    public static function getters()
    {
        return self::$getters;
    }

    const CURRENCY_AUD = 'AUD';
    const CURRENCY_NZD = 'NZD';
    const FRAUD_CHECK_RESULT_PASS = 'pass';
    const FRAUD_CHECK_RESULT_FAIL = 'fail';
    const FRAUD_CHECK_RESULT_UNKNOWN = 'unknown';

    /**
     * Gets allowable values of the enum
     * @return string[]
     */
    public function getCurrencyAllowableValues()
    {
        return array(
            self::CURRENCY_AUD,
            self::CURRENCY_NZD,
        );
    }

    /**
     * Gets allowable values of the enum
     * @return string[]
     */
    public function getFraudCheckResultAllowableValues()
    {
        return array(
            self::FRAUD_CHECK_RESULT_PASS,
            self::FRAUD_CHECK_RESULT_FAIL,
            self::FRAUD_CHECK_RESULT_UNKNOWN,
        );
    }

    /**
     * Associative array for storing property values
     * @var mixed[]
     */
    protected $container = array();

    /**
     * Constructor
     * @param mixed[] $data Associated array of property values initializing the model
     */
    public function __construct(array $data = null)
    {
        $this->container['account_created'] = isset($data['account_created']) ? $data['account_created'] : null;
        $this->container['sales_total_count'] = isset($data['sales_total_count']) ? $data['sales_total_count'] : null;
        $this->container['sales_total_amount'] = isset($data['sales_total_amount']) ? $data['sales_total_amount'] : null;
        $this->container['sales_avg_amount'] = isset($data['sales_avg_amount']) ? $data['sales_avg_amount'] : null;
        $this->container['sales_max_amount'] = isset($data['sales_max_amount']) ? $data['sales_max_amount'] : null;
        $this->container['refunds_total_amount'] = isset($data['refunds_total_amount']) ? $data['refunds_total_amount'] : null;
        $this->container['previous_chargeback'] = isset($data['previous_chargeback']) ? $data['previous_chargeback'] : null;
        $this->container['currency'] = isset($data['currency']) ? $data['currency'] : null;
        $this->container['last_login'] = isset($data['last_login']) ? $data['last_login'] : null;
        $this->container['has_previous_purchases'] = isset($data['has_previous_purchases']) ? $data['has_previous_purchases'] : null;
        $this->container['fraud_check_result'] = isset($data['fraud_check_result']) ? $data['fraud_check_result'] : null;
    }

    /**
     * show all the invalid properties with reasons.
     *
     * @return array invalid properties with reasons
     */
    public function listInvalidProperties()
    {
        $invalid_properties = array();

        $allowed_values = array("AUD", "NZD");
        if (!in_array($this->container['currency'], $allowed_values)) {
            $invalid_properties[] = "invalid value for 'currency', must be one of 'AUD', 'NZD'.";
        }

        $allowed_values = array("pass", "fail", "unknown");
        if (!in_array($this->container['fraud_check_result'], $allowed_values)) {
            $invalid_properties[] = "invalid value for 'fraud_check_result', must be one of 'pass', 'fail', 'unknown'.";
        }

        return $invalid_properties;
    }

    /**
     * validate all the properties in the model
     * return true if all passed
     *
     * @return bool True if all properties are valid
     */
    public function valid()
    {

        $allowed_values = array("AUD", "NZD");
        if (!in_array($this->container['currency'], $allowed_values)) {
            return false;
        }
        $allowed_values = array("pass", "fail", "unknown");
        if (!in_array($this->container['fraud_check_result'], $allowed_values)) {
            return false;
        }
        return true;
    }

    /**
     * Gets account_created
     * @return \DateTime
     */
    public function getAccountCreated()
    {
        return $this->container['account_created'];
    }

    /**
     * Sets account_created
     * @param \DateTime $account_created The time at which the shopper's account was created
     * @return $this
     */
    public function setAccountCreated($account_created)
    {
        $this->container['account_created'] = $account_created;

        return $this;
    }

    /**
     * Gets sales_total_count
     * @return int
     */
    public function getSalesTotalCount()
    {
        return $this->container['sales_total_count'];
    }

    /**
     * Sets sales_total_count
     * @param int $sales_total_count The total number of separate purchases the shopper has made through the store
     * @return $this
     */
    public function setSalesTotalCount($sales_total_count)
    {
        $this->container['sales_total_count'] = $sales_total_count;

        return $this;
    }

    /**
     * Gets sales_total_amount
     * @return float
     */
    public function getSalesTotalAmount()
    {
        return $this->container['sales_total_amount'];
    }

    /**
     * Sets sales_total_amount
     * @param float $sales_total_amount The total purchase amount of all orders previously captured through the store.
     * @return $this
     */
    public function setSalesTotalAmount($sales_total_amount)
    {
        $this->container['sales_total_amount'] = $sales_total_amount;

        return $this;
    }

    /**
     * Gets sales_avg_amount
     * @return float
     */
    public function getSalesAvgAmount()
    {
        return $this->container['sales_avg_amount'];
    }

    /**
     * Sets sales_avg_amount
     * @param float $sales_avg_amount The average value of sales made by the shopper through the store
     * @return $this
     */
    public function setSalesAvgAmount($sales_avg_amount)
    {
        $this->container['sales_avg_amount'] = $sales_avg_amount;

        return $this;
    }

    /**
     * Gets sales_max_amount
     * @return float
     */
    public function getSalesMaxAmount()
    {
        return $this->container['sales_max_amount'];
    }

    /**
     * Sets sales_max_amount
     * @param float $sales_max_amount The maximum purchase amount the shopper has previously purchased from the store.
     * @return $this
     */
    public function setSalesMaxAmount($sales_max_amount)
    {
        $this->container['sales_max_amount'] = $sales_max_amount;

        return $this;
    }

    /**
     * Gets refunds_total_amount
     * @return float
     */
    public function getRefundsTotalAmount()
    {
        return $this->container['refunds_total_amount'];
    }

    /**
     * Sets refunds_total_amount
     * @param float $refunds_total_amount The total amount of all refunds linked to this shopper's account
     * @return $this
     */
    public function setRefundsTotalAmount($refunds_total_amount)
    {
        $this->container['refunds_total_amount'] = $refunds_total_amount;

        return $this;
    }

    /**
     * Gets previous_chargeback
     * @return bool
     */
    public function getPreviousChargeback()
    {
        return $this->container['previous_chargeback'];
    }

    /**
     * Sets previous_chargeback
     * @param bool $previous_chargeback Has the shopper had a previous chargeback?
     * @return $this
     */
    public function setPreviousChargeback($previous_chargeback)
    {
        $this->container['previous_chargeback'] = $previous_chargeback;

        return $this;
    }

    /**
     * Gets currency
     * @return string
     */
    public function getCurrency()
    {
        return $this->container['currency'];
    }

    /**
     * Sets currency
     * @param string $currency The currency of all all amount values
     * @return $this
     */
    public function setCurrency($currency)
    {
        $allowed_values = array('AUD', 'NZD');
        if (!is_null($currency) && (!in_array($currency, $allowed_values))) {
            throw new \InvalidArgumentException("Invalid value for 'currency', must be one of 'AUD', 'NZD'");
        }
        $this->container['currency'] = $currency;

        return $this;
    }

    /**
     * Gets last_login
     * @return \DateTime
     */
    public function getLastLogin()
    {
        return $this->container['last_login'];
    }

    /**
     * Sets last_login
     * @param \DateTime $last_login The date at which the shopper last logged in to your store.
     * @return $this
     */
    public function setLastLogin($last_login)
    {
        $this->container['last_login'] = $last_login;

        return $this;
    }

    /**
     * Gets has_previous_purchases
     * @return bool
     */
    public function getHasPreviousPurchases()
    {
        return $this->container['has_previous_purchases'];
    }

    /**
     * Sets has_previous_purchases
     * @param bool $has_previous_purchases Does this customer have previous purchases at your store?
     * @return $this
     */
    public function setHasPreviousPurchases($has_previous_purchases)
    {
        $this->container['has_previous_purchases'] = $has_previous_purchases;

        return $this;
    }

    /**
     * Gets fraud_check_result
     * @return string
     */
    public function getFraudCheckResult()
    {
        return $this->container['fraud_check_result'];
    }

    /**
     * Sets fraud_check_result
     * @param string $fraud_check_result Merchant system's fraud check result
     * @return $this
     */
    public function setFraudCheckResult($fraud_check_result)
    {
        $allowed_values = array('pass', 'fail', 'unknown');
        if (!is_null($fraud_check_result) && (!in_array($fraud_check_result, $allowed_values))) {
            throw new \InvalidArgumentException("Invalid value for 'fraud_check_result', must be one of 'pass', 'fail', 'unknown'");
        }
        $this->container['fraud_check_result'] = $fraud_check_result;

        return $this;
    }
    /**
     * Returns true if offset exists. False otherwise.
     * @param  integer $offset Offset
     * @return boolean
     */
    public function offsetExists($offset)
    {
        return isset($this->container[$offset]);
    }

    /**
     * Gets offset.
     * @param  integer $offset Offset
     * @return mixed
     */
    public function offsetGet($offset)
    {
        return isset($this->container[$offset]) ? $this->container[$offset] : null;
    }

    /**
     * Sets value based on offset.
     * @param  integer $offset Offset
     * @param  mixed   $value  Value to be set
     * @return void
     */
    public function offsetSet($offset, $value)
    {
        if (is_null($offset)) {
            $this->container[] = $value;
        } else {
            $this->container[$offset] = $value;
        }
    }

    /**
     * Unsets offset.
     * @param  integer $offset Offset
     * @return void
     */
    public function offsetUnset($offset)
    {
        unset($this->container[$offset]);
    }

    /**
     * Gets the string presentation of the object
     * @return string
     */
    public function __toString()
    {
        if (defined('JSON_PRETTY_PRINT')) { // use JSON pretty print
            return json_encode(\zipMoney\ObjectSerializer::sanitizeForSerialization($this), JSON_PRETTY_PRINT);
        }

        return json_encode(\zipMoney\ObjectSerializer::sanitizeForSerialization($this));
    }
}


<?php
/**
 * Configuration
 *
 * @category Class
 * @package  zipMoney
 * @author   zipMoney Payments Pty Ltd
 * @link     https://github.com/zipMoney/merchantapi-php
 */

namespace zipMoney;

class Configuration
{
    private static $defaultConfiguration = null;

    /**
     * Associate array to store API key(s)
     *
     * @var string[]
     */
    protected $apiKeys = array();

    /**
     * Associate array to store API prefix (e.g. Bearer)
     *
     * @var string[]
     */
    protected $apiKeyPrefixes = array();

    /**
     * Access token for OAuth
     *
     * @var string
     */
    protected $accessToken = '';

    /**
     * Username for HTTP basic authentication
     *
     * @var string
     */
    protected $username = '';

    /**
     * Password for HTTP basic authentication
     *
     * @var string
     */
    protected $password = '';

    /**
     * The default header(s)
     *
     * @var array
     */
    protected $defaultHeaders = array();

    /**
     * The host
     *
     * @var string
     */
    protected $host = 'https://api.zipmoney.com.au/merchant/v1';

    /**
     * API Version
     *
     * @var string
     */
    protected $api_version = "2017-03-01";

    /**
     * Platform
     *
     * @var string
     */
    protected $platform = null;

    /**
     * The environments
     *
     * @var array
     */
    protected $supportedEnvironments = array(
        "sandbox" => array("host" => "https://api.sandbox.zipmoney.com.au/merchant/v1"),
        "production" => array("host" => 'https://api.zipmoney.com.au/merchant/v1')
    );

    /**
     * The default enviornment to be used
     *
     * @var string
     */
    protected $environment = "production";

    /**
     * Timeout (second) of the HTTP request, by default set to 0, no timeout
     *
     * @var string
     */
    protected $curlTimeout = 0;

    /**
     * Number of retries allowed if the first one fails.
     *
     * @var string
     */
    protected $curlNumRetries = 3;

    /**
     * Number of retries allowed if the first one fails.
     *
     * @var string
     */
    protected $retryInterval = 0;

    /**
     * Timeout (second) of the HTTP connection, by default set to 0, no timeout
     *
     * @var string
     */
    protected $curlConnectTimeout = 0;

    /**
     * User agent of the HTTP request, set to "merchantapi-php" by default
     *
     * @var string
     */
    protected $userAgent = "merchantapi-php/1.0.0/php";

    /**
     * Debug switch (default set to false)
     *
     * @var bool
     */
    protected $debug = false;

    /**
     * Debug file location (log to STDOUT by default)
     *
     * @var string
     */
    protected $debugFile = 'php://output';

    /**
     * Debug file location (log to STDOUT by default)
     *
     * @var string
     */
    protected $tempFolderPath;

    /**
     * Indicates if SSL verification should be enabled or disabled.
     *
     * This is useful if the host uses a self-signed SSL certificate.
     *
     * @var boolean True if the certificate should be validated, false otherwise.
     */
    protected $sslVerification = true;

    /**
     * Curl proxy host
     *
     * @var string
     */
    protected $proxyHost;

    /**
     * Curl proxy port
     *
     * @var integer
     */
    protected $proxyPort;

    /**
     * Curl proxy type, e.g. CURLPROXY_HTTP or CURLPROXY_SOCKS5
     *
     * @see https://secure.php.net/manual/en/function.curl-setopt.php
     * @var integer
     */
    protected $proxyType;

    /**
     * Curl proxy username
     *
     * @var string
     */
    protected $proxyUser;

    /**
     * Curl proxy password
     *
     * @var string
     */
    protected $proxyPassword;

    /**
     * Constructor
     */
    public function __construct()
    {
        $this->tempFolderPath = sys_get_temp_dir();
    }

    /**
     * Sets API key
     *
     * @param string $apiKeyIdentifier API key identifier (authentication scheme)
     * @param string $key              API key or token
     *
     * @return Configuration
     */
    public function setApiKey($apiKeyIdentifier, $key)
    {
        $this->apiKeys[$apiKeyIdentifier] = $key;
        return $this;
    }

    /**
     * Gets API key
     *
     * @param string $apiKeyIdentifier API key identifier (authentication scheme)
     *
     * @return string API key or token
     */
    public function getApiKey($apiKeyIdentifier)
    {
        return isset($this->apiKeys[$apiKeyIdentifier]) ? $this->apiKeys[$apiKeyIdentifier] : null;
    }

    /**
     * Sets the prefix for API key (e.g. Bearer)
     *
     * @param string $apiKeyIdentifier API key identifier (authentication scheme)
     * @param string $prefix           API key prefix, e.g. Bearer
     *
     * @return Configuration
     */
    public function setApiKeyPrefix($apiKeyIdentifier, $prefix)
    {
        $this->apiKeyPrefixes[$apiKeyIdentifier] = $prefix;
        return $this;
    }

    /**
     * Gets API key prefix
     *
     * @param string $apiKeyIdentifier API key identifier (authentication scheme)
     *
     * @return string
     */
    public function getApiKeyPrefix($apiKeyIdentifier)
    {
        return isset($this->apiKeyPrefixes[$apiKeyIdentifier]) ? $this->apiKeyPrefixes[$apiKeyIdentifier] : null;
    }

    /**
     * Sets the access token for OAuth
     *
     * @param string $accessToken Token for OAuth
     *
     * @return Configuration
     */
    public function setAccessToken($accessToken)
    {
        $this->accessToken = $accessToken;
        return $this;
    }

    /**
     * Gets the access token for OAuth
     *
     * @return string Access token for OAuth
     */
    public function getAccessToken()
    {
        return $this->accessToken;
    }

    /**
     * Sets the username for HTTP basic authentication
     *
     * @param string $username Username for HTTP basic authentication
     *
     * @return Configuration
     */
    public function setUsername($username)
    {
        $this->username = $username;
        return $this;
    }

    /**
     * Gets the username for HTTP basic authentication
     *
     * @return string Username for HTTP basic authentication
     */
    public function getUsername()
    {
        return $this->username;
    }

    /**
     * Sets the password for HTTP basic authentication
     *
     * @param string $password Password for HTTP basic authentication
     *
     * @return Configuration
     */
    public function setPassword($password)
    {
        $this->password = $password;
        return $this;
    }

    /**
     * Gets the password for HTTP basic authentication
     *
     * @return string Password for HTTP basic authentication
     */
    public function getPassword()
    {
        return $this->password;
    }

    /**
     * Adds a default header
     *
     * @param string $headerName  header name (e.g. Token)
     * @param string $headerValue header value (e.g. 1z8wp3)
     *
     * @return Configuration
     */
    public function addDefaultHeader($headerName, $headerValue)
    {
        if (!is_string($headerName)) {
            throw new \InvalidArgumentException('Header name must be a string.');
        }

        $this->defaultHeaders[$headerName] =  $headerValue;
        return $this;
    }

    /**
     * Gets the default header
     *
     * @return array An array of default header(s)
     */
    public function getDefaultHeaders()
    {
        return $this->defaultHeaders;
    }

    /**
     * Deletes a default header
     *
     * @param string $headerName the header to delete
     *
     * @return Configuration
     */
    public function deleteDefaultHeader($headerName)
    {
        unset($this->defaultHeaders[$headerName]);
    }

    /**
     * Sets the host
     *
     * @param string $host Host
     *
     * @return Configuration
     */
    public function setHost($host)
    {
        $this->host = $host;
        return $this;
    }

    /**
     * Gets the host
     *
     * @return string Host
     */
    public function getHost()
    {
        return $this->host;
    }

    /**
     * Sets the user agent of the api client
     *
     * @param string $userAgent the user agent of the api client
     *
     * @return Configuration
     */
    public function setUserAgent($userAgent)
    {
        if (!is_string($userAgent)) {
            throw new \InvalidArgumentException('User-agent must be a string.');
        }

        $this->userAgent = $userAgent;
        return $this;
    }

    /**
     * Gets the user agent of the api client
     *
     * @return string user agent
     */
    public function getUserAgent()
    {
        return $this->userAgent;
    }

    /**
     * Sets the HTTP timeout value
     *
     * @param integer $seconds Number of seconds before timing out [set to 0 for no timeout]
     *
     * @return Configuration
     */
    public function setCurlTimeout($seconds)
    {
        if (!is_numeric($seconds) || $seconds < 0) {
            throw new \InvalidArgumentException('Timeout value must be numeric and a non-negative number.');
        }

        $this->curlTimeout = $seconds;
        return $this;
    }

    /**
     * Gets the HTTP timeout value
     *
     * @return string HTTP timeout value
     */
    public function getCurlTimeout()
    {
        return $this->curlTimeout;
    }

    /**
     * Sets the retry value
     *
     * @param integer  Number of retries before it gives up
     *
     * @return Configuration
     */
    public function setCurlNumRetries($retries)
    {
        if (!is_numeric($retries) || $retries < 0) {
            throw new \InvalidArgumentException('Retries value must be numeric and a non-negative number.');
        }

        $this->curlNumRetries = $retries;
        return $this;
    }

    /**
     * Gets the retry value
     *
     * @return string HTTP timeout value
     */
    public function getCurlNumRetries()
    {
        return $this->curlNumRetries;
    }

    /**
     * Sets the HTTP connect timeout value
     *
     * @param integer $seconds Number of seconds before connection times out [set to 0 for no timeout]
     *
     * @return Configuration
     */
    public function setCurlConnectTimeout($seconds)
    {
        if (!is_numeric($seconds) || $seconds < 0) {
            throw new \InvalidArgumentException('Connect timeout value must be numeric and a non-negative number.');
        }

        $this->curlConnectTimeout = $seconds;
        return $this;
    }

    /**
     * Gets the HTTP connect timeout value
     *
     * @return string HTTP connect timeout value
     */
    public function getCurlConnectTimeout()
    {
        return $this->curlConnectTimeout;
    }

    /**
     * Sets the Retry Interval Value
     *
     * @param integer $retryInterval HTTP Proxy Port
     *
     * @return ApiClient
     */
    public function setRetryInterval($retryInterval)
    {
        $this->retryInterval = $retryInterval;
        return $this;
    }

    /**
     * Gets the Retry Interval Value
     *
     * @param integer Retry Interval Value
     */
    public function getRetryInterval()
    {
        return $this->retryInterval;
    }

    /**
     * Sets the HTTP Proxy Host
     *
     * @param string $proxyHost HTTP Proxy URL
     *
     * @return ApiClient
     */
    public function setCurlProxyHost($proxyHost)
    {
        $this->proxyHost = $proxyHost;
        return $this;
    }

    /**
     * Gets the HTTP Proxy Host
     *
     * @return string
     */
    public function getCurlProxyHost()
    {
        return $this->proxyHost;
    }

    /**
     * Sets the HTTP Proxy Port
     *
     * @param integer $proxyPort HTTP Proxy Port
     *
     * @return ApiClient
     */
    public function setCurlProxyPort($proxyPort)
    {
        $this->proxyPort = $proxyPort;
        return $this;
    }

    /**
     * Gets the HTTP Proxy Port
     *
     * @return integer
     */
    public function getCurlProxyPort()
    {
        return $this->proxyPort;
    }

    /**
     * Sets the HTTP Proxy Type
     *
     * @param integer $proxyType HTTP Proxy Type
     *
     * @return ApiClient
     */
    public function setCurlProxyType($proxyType)
    {
        $this->proxyType = $proxyType;
        return $this;
    }

    /**
     * Gets the HTTP Proxy Type
     *
     * @return integer
     */
    public function getCurlProxyType()
    {
        return $this->proxyType;
    }

    /**
     * Sets the HTTP Proxy User
     *
     * @param string $proxyUser HTTP Proxy User
     *
     * @return ApiClient
     */
    public function setCurlProxyUser($proxyUser)
    {
        $this->proxyUser = $proxyUser;
        return $this;
    }

    /**
     * Gets the HTTP Proxy User
     *
     * @return string
     */
    public function getCurlProxyUser()
    {
        return $this->proxyUser;
    }

    /**
     * Sets the HTTP Proxy Password
     *
     * @param string $proxyPassword HTTP Proxy Password
     *
     * @return ApiClient
     */
    public function setCurlProxyPassword($proxyPassword)
    {
        $this->proxyPassword = $proxyPassword;
        return $this;
    }

    /**
     * Gets the HTTP Proxy Password
     *
     * @return string
     */
    public function getCurlProxyPassword()
    {
        return $this->proxyPassword;
    }

    /**
     * Sets debug flag
     *
     * @param bool $debug Debug flag
     *
     * @return Configuration
     */
    public function setDebug($debug)
    {
        $this->debug = $debug;
        return $this;
    }

    /**
     * Gets the environment
     *
     * @return bool
     */
    public function getEnvironment()
    {
        return $this->environment;
    }

    /**
     * Sets the environment
     *
     * @param bool $environment
     *
     * @return Configuration
     */
    public function setEnvironment($environment)
    {
        $this->environment = $environment;

        $host = $this->supportedEnvironments['production']['host'];

        if(in_array($environment,array_keys($this->supportedEnvironments))){
            $host = $this->supportedEnvironments[$environment]['host'];
        }

        $this->setHost($host);

        return $this;
    }

    /**
     * Gets the debug flag
     *
     * @return bool
     */
    public function getDebug()
    {
        return $this->debug;
    }

    /**
     * Sets the debug file
     *
     * @param string $debugFile Debug file
     *
     * @return Configuration
     */
    public function setDebugFile($debugFile)
    {
        $this->debugFile = $debugFile;
        return $this;
    }

    /**
     * Gets the debug file
     *
     * @return string
     */
    public function getDebugFile()
    {
        return $this->debugFile;
    }

    /**
     * Sets the temp folder path
     *
     * @param string $tempFolderPath Temp folder path
     *
     * @return Configuration
     */
    public function setTempFolderPath($tempFolderPath)
    {
        $this->tempFolderPath = $tempFolderPath;
        return $this;
    }

    /**
     * Gets the temp folder path
     *
     * @return string Temp folder path
     */
    public function getTempFolderPath()
    {
        return $this->tempFolderPath;
    }

    /**
     * Sets if SSL verification should be enabled or disabled
     *
     * @param boolean $sslVerification True if the certificate should be validated, false otherwise
     *
     * @return Configuration
     */
    public function setSSLVerification($sslVerification)
    {
        $this->sslVerification = $sslVerification;
        return $this;
    }

    /**
     * Gets if SSL verification should be enabled or disabled
     *
     * @return boolean True if the certificate should be validated, false otherwise
     */
    public function getSSLVerification()
    {
        return $this->sslVerification;
    }

    /**
     * Gets the default configuration instance
     *
     * @return Configuration
     */
    public static function getDefaultConfiguration()
    {
        if (self::$defaultConfiguration === null) {
            self::$defaultConfiguration = new Configuration();
        }

        return self::$defaultConfiguration;
    }

    /**
     * Sets the detault configuration instance
     *
     * @param Configuration $config An instance of the Configuration Object
     *
     * @return void
     */
    public static function setDefaultConfiguration(Configuration $config)
    {
        self::$defaultConfiguration = $config;
    }

    /**
     * Gets the essential information for debugging
     *
     * @return string The report for debugging
     */
    public static function toDebugReport()
    {
        $report  = 'PHP SDK (zipMoney) Debug Report:' . PHP_EOL;
        $report .= '    OS: ' . php_uname() . PHP_EOL;
        $report .= '    PHP Version: ' . phpversion() . PHP_EOL;
        $report .= '    OpenAPI Spec Version: 2017-03-01' . PHP_EOL;
        $report .= '    Temp Folder Path: ' . self::getDefaultConfiguration()->getTempFolderPath() . PHP_EOL;

        return $report;
    }

      /**
     * Sets the platform the library is being used
     *
     * @param string $platform
     *
     * @return ApiClient
     */
    public function setPlatform($platform)
    {
        $this->platform = $platform;
        return $this;
    }

    /**
     * Gets the platform
     *
     * @return string
     */
    public function getPlatform()
    {
        return $this->platform;
    }

    /**
     * Add the api version
     *
     * @return Configuration
     */
    public function setApiVersion($version)
    {
        $this->defaultHeaders["Zip-Version"] =  $version;

        return $this;
    }

    public function setDefaultHeaders()
    {
        $user_agent_array = array();

        if( $platform = $this->getPlatform() ){
          $user_agent_array[] = $platform;
        }

        $default_user_agent = "merchantapi-php";

        if( $package_version = $this->getPackageVersion() ){
           $user_agent_array[] = $default_user_agent."/".$package_version;
        } else {
           $user_agent_array[] = $default_user_agent;
        }

        $user_agent = implode(" ",$user_agent_array);

        $this->setUserAgent($user_agent);
        $this->setApiVersion($this->api_version);

    }

    /**
     * Retrieves the pacakge version
     *
     * @return string
     */
    public function getPackageVersion()
    {
        $package_config  = file_get_contents(dirname(__FILE__)."./../composer.json");

        if($package_config){
            $package_config_object = json_decode($package_config);
            if(is_object($package_config_object) && isset($package_config_object->version)){
                return $package_config_object->version;
            }
        }
        return null;
    }
}


<?php
/**
 * OrderShippingTracking
 *
 * @category Class
 * @package  zipMoney
 * @author   zipMoney Payments Pty Ltd
 * @link     https://github.com/zipMoney/merchantapi-php
 */

namespace zipMoney\Model;

use \ArrayAccess;

class OrderShippingTracking implements ArrayAccess
{
    const DISCRIMINATOR = 'subclass';

    /**
      * The original name of the model.
      * @var string
      */
    protected static $swaggerModelName = 'OrderShipping_tracking';

    /**
      * Array of property to type mappings. Used for (de)serialization
      * @var string[]
      */
    protected static $zipTypes = array(
        'uri' => 'string',
        'number' => 'string',
        'carrier' => 'string'
    );

    public static function zipTypes()
    {
        return self::$zipTypes;
    }

    /**
     * Array of attributes where the key is the local name, and the value is the original name
     * @var string[]
     */
    protected static $attributeMap = array(
        'uri' => 'uri',
        'number' => 'number',
        'carrier' => 'carrier'
    );

    /**
     * Array of attributes to setter functions (for deserialization of responses)
     * @var string[]
     */
    protected static $setters = array(
        'uri' => 'setUri',
        'number' => 'setNumber',
        'carrier' => 'setCarrier'
    );

    /**
     * Array of attributes to getter functions (for serialization of requests)
     * @var string[]
     */
    protected static $getters = array(
        'uri' => 'getUri',
        'number' => 'getNumber',
        'carrier' => 'getCarrier'
    );

    public static function attributeMap()
    {
        return self::$attributeMap;
    }

    public static function setters()
    {
        return self::$setters;
    }

    public static function getters()
    {
        return self::$getters;
    }

    /**
     * Associative array for storing property values
     * @var mixed[]
     */
    protected $container = array();

    /**
     * Constructor
     * @param mixed[] $data Associated array of property values initializing the model
     */
    public function __construct(array $data = null)
    {
        $this->container['uri'] = isset($data['uri']) ? $data['uri'] : null;
        $this->container['number'] = isset($data['number']) ? $data['number'] : null;
        $this->container['carrier'] = isset($data['carrier']) ? $data['carrier'] : null;
    }

    /**
     * show all the invalid properties with reasons.
     *
     * @return array invalid properties with reasons
     */
    public function listInvalidProperties()
    {
        $invalid_properties = array();

        if (!is_null($this->container['uri']) && (strlen($this->container['uri']) > 500)) {
            $invalid_properties[] = "invalid value for 'uri', the character length must be smaller than or equal to 500.";
        }

        if (!is_null($this->container['number']) && (strlen($this->container['number']) > 120)) {
            $invalid_properties[] = "invalid value for 'number', the character length must be smaller than or equal to 120.";
        }

        if (!is_null($this->container['carrier']) && (strlen($this->container['carrier']) > 120)) {
            $invalid_properties[] = "invalid value for 'carrier', the character length must be smaller than or equal to 120.";
        }

        return $invalid_properties;
    }

    /**
     * validate all the properties in the model
     * return true if all passed
     *
     * @return bool True if all properties are valid
     */
    public function valid()
    {

        if (strlen($this->container['uri']) > 500) {
            return false;
        }
        if (strlen($this->container['number']) > 120) {
            return false;
        }
        if (strlen($this->container['carrier']) > 120) {
            return false;
        }
        return true;
    }

    /**
     * Gets uri
     * @return string
     */
    public function getUri()
    {
        return $this->container['uri'];
    }

    /**
     * Sets uri
     * @param string $uri
     * @return $this
     */
    public function setUri($uri)
    {
        if (!is_null($uri) && (strlen($uri) > 500)) {
            throw new \InvalidArgumentException('invalid length for $uri when calling OrderShippingTracking., must be smaller than or equal to 500.');
        }

        $this->container['uri'] = $uri;

        return $this;
    }

    /**
     * Gets number
     * @return string
     */
    public function getNumber()
    {
        return $this->container['number'];
    }

    /**
     * Sets number
     * @param string $number
     * @return $this
     */
    public function setNumber($number)
    {
        if (!is_null($number) && (strlen($number) > 120)) {
            throw new \InvalidArgumentException('invalid length for $number when calling OrderShippingTracking., must be smaller than or equal to 120.');
        }

        $this->container['number'] = $number;

        return $this;
    }

    /**
     * Gets carrier
     * @return string
     */
    public function getCarrier()
    {
        return $this->container['carrier'];
    }

    /**
     * Sets carrier
     * @param string $carrier
     * @return $this
     */
    public function setCarrier($carrier)
    {
        if (!is_null($carrier) && (strlen($carrier) > 120)) {
            throw new \InvalidArgumentException('invalid length for $carrier when calling OrderShippingTracking., must be smaller than or equal to 120.');
        }

        $this->container['carrier'] = $carrier;

        return $this;
    }
    /**
     * Returns true if offset exists. False otherwise.
     * @param  integer $offset Offset
     * @return boolean
     */
    public function offsetExists($offset)
    {
        return isset($this->container[$offset]);
    }

    /**
     * Gets offset.
     * @param  integer $offset Offset
     * @return mixed
     */
    public function offsetGet($offset)
    {
        return isset($this->container[$offset]) ? $this->container[$offset] : null;
    }

    /**
     * Sets value based on offset.
     * @param  integer $offset Offset
     * @param  mixed   $value  Value to be set
     * @return void
     */
    public function offsetSet($offset, $value)
    {
        if (is_null($offset)) {
            $this->container[] = $value;
        } else {
            $this->container[$offset] = $value;
        }
    }

    /**
     * Unsets offset.
     * @param  integer $offset Offset
     * @return void
     */
    public function offsetUnset($offset)
    {
        unset($this->container[$offset]);
    }

    /**
     * Gets the string presentation of the object
     * @return string
     */
    public function __toString()
    {
        if (defined('JSON_PRETTY_PRINT')) { // use JSON pretty print
            return json_encode(\zipMoney\ObjectSerializer::sanitizeForSerialization($this), JSON_PRETTY_PRINT);
        }

        return json_encode(\zipMoney\ObjectSerializer::sanitizeForSerialization($this));
    }
}


<?php
/**
 * Shopper
 *
 * @category Class
 * @package  zipMoney
 * @author   zipMoney Payments Pty Ltd
 * @link     https://github.com/zipMoney/merchantapi-php
 */

namespace zipMoney\Model;

use \ArrayAccess;

class Shopper implements ArrayAccess
{
    const DISCRIMINATOR = 'subclass';

    /**
      * The original name of the model.
      * @var string
      */
    protected static $swaggerModelName = 'Shopper';

    /**
      * Array of property to type mappings. Used for (de)serialization
      * @var string[]
      */
    protected static $zipTypes = array(
        'title' => 'string',
        'first_name' => 'string',
        'last_name' => 'string',
        'middle_name' => 'string',
        'phone' => 'string',
        'email' => 'string',
        'birth_date' => '\DateTime',
        'gender' => 'string',
        'statistics' => '\zipMoney\Model\ShopperStatistics',
        'billing_address' => '\zipMoney\Model\Address'
    );

    public static function zipTypes()
    {
        return self::$zipTypes;
    }

    /**
     * Array of attributes where the key is the local name, and the value is the original name
     * @var string[]
     */
    protected static $attributeMap = array(
        'title' => 'title',
        'first_name' => 'first_name',
        'last_name' => 'last_name',
        'middle_name' => 'middle_name',
        'phone' => 'phone',
        'email' => 'email',
        'birth_date' => 'birth_date',
        'gender' => 'gender',
        'statistics' => 'statistics',
        'billing_address' => 'billing_address'
    );

    /**
     * Array of attributes to setter functions (for deserialization of responses)
     * @var string[]
     */
    protected static $setters = array(
        'title' => 'setTitle',
        'first_name' => 'setFirstName',
        'last_name' => 'setLastName',
        'middle_name' => 'setMiddleName',
        'phone' => 'setPhone',
        'email' => 'setEmail',
        'birth_date' => 'setBirthDate',
        'gender' => 'setGender',
        'statistics' => 'setStatistics',
        'billing_address' => 'setBillingAddress'
    );

    /**
     * Array of attributes to getter functions (for serialization of requests)
     * @var string[]
     */
    protected static $getters = array(
        'title' => 'getTitle',
        'first_name' => 'getFirstName',
        'last_name' => 'getLastName',
        'middle_name' => 'getMiddleName',
        'phone' => 'getPhone',
        'email' => 'getEmail',
        'birth_date' => 'getBirthDate',
        'gender' => 'getGender',
        'statistics' => 'getStatistics',
        'billing_address' => 'getBillingAddress'
    );

    public static function attributeMap()
    {
        return self::$attributeMap;
    }

    public static function setters()
    {
        return self::$setters;
    }

    public static function getters()
    {
        return self::$getters;
    }

    const GENDER_MALE = 'Male';
    const GENDER_FEMALE = 'Female';
    const GENDER_OTHER = 'Other';

    /**
     * Gets allowable values of the enum
     * @return string[]
     */
    public function getGenderAllowableValues()
    {
        return array(
            self::GENDER_MALE,
            self::GENDER_FEMALE,
            self::GENDER_OTHER,
        );
    }

    /**
     * Associative array for storing property values
     * @var mixed[]
     */
    protected $container = array();

    /**
     * Constructor
     * @param mixed[] $data Associated array of property values initializing the model
     */
    public function __construct(array $data = null)
    {
        $this->container['title'] = isset($data['title']) ? $data['title'] : null;
        $this->container['first_name'] = isset($data['first_name']) ? $data['first_name'] : null;
        $this->container['last_name'] = isset($data['last_name']) ? $data['last_name'] : null;
        $this->container['middle_name'] = isset($data['middle_name']) ? $data['middle_name'] : null;
        $this->container['phone'] = isset($data['phone']) ? $data['phone'] : null;
        $this->container['email'] = isset($data['email']) ? $data['email'] : null;
        $this->container['birth_date'] = isset($data['birth_date']) ? $data['birth_date'] : null;
        $this->container['gender'] = isset($data['gender']) ? $data['gender'] : null;
        $this->container['statistics'] = isset($data['statistics']) ? $data['statistics'] : null;
        $this->container['billing_address'] = isset($data['billing_address']) ? $data['billing_address'] : null;
    }

    /**
     * show all the invalid properties with reasons.
     *
     * @return array invalid properties with reasons
     */
    public function listInvalidProperties()
    {
        $invalid_properties = array();

        if ($this->container['first_name'] === null) {
            $invalid_properties[] = "'first_name' can't be null";
        }
        if ($this->container['last_name'] === null) {
            $invalid_properties[] = "'last_name' can't be null";
        }
        if (!is_null($this->container['phone']) && !preg_match("/^\\+?[\\d\\s]+$/", $this->container['phone'])) {
            $invalid_properties[] = "invalid value for 'phone', must be conform to the pattern /^\\+?[\\d\\s]+$/.";
        }

        if ($this->container['email'] === null) {
            $invalid_properties[] = "'email' can't be null";
        }
        $allowed_values = array("Male", "Female", "Other");
        if (!in_array($this->container['gender'], $allowed_values)) {
            $invalid_properties[] = "invalid value for 'gender', must be one of 'Male', 'Female', 'Other'.";
        }

        if ($this->container['billing_address'] === null) {
            $invalid_properties[] = "'billing_address' can't be null";
        }
        return $invalid_properties;
    }

    /**
     * validate all the properties in the model
     * return true if all passed
     *
     * @return bool True if all properties are valid
     */
    public function valid()
    {

        if ($this->container['first_name'] === null) {
            return false;
        }
        if ($this->container['last_name'] === null) {
            return false;
        }
        if (!preg_match("/^\\+?[\\d\\s]+$/", $this->container['phone'])) {
            return false;
        }
        if ($this->container['email'] === null) {
            return false;
        }
        $allowed_values = array("Male", "Female", "Other");
        if (!in_array($this->container['gender'], $allowed_values)) {
            return false;
        }
        if ($this->container['billing_address'] === null) {
            return false;
        }
        return true;
    }

    /**
     * Gets title
     * @return string
     */
    public function getTitle()
    {
        return $this->container['title'];
    }

    /**
     * Sets title
     * @param string $title The shopper's title
     * @return $this
     */
    public function setTitle($title)
    {
        $this->container['title'] = $title;

        return $this;
    }

    /**
     * Gets first_name
     * @return string
     */
    public function getFirstName()
    {
        return $this->container['first_name'];
    }

    /**
     * Sets first_name
     * @param string $first_name The shopper's first name
     * @return $this
     */
    public function setFirstName($first_name)
    {
        $this->container['first_name'] = $first_name;

        return $this;
    }

    /**
     * Gets last_name
     * @return string
     */
    public function getLastName()
    {
        return $this->container['last_name'];
    }

    /**
     * Sets last_name
     * @param string $last_name The shopper's last name
     * @return $this
     */
    public function setLastName($last_name)
    {
        $this->container['last_name'] = $last_name;

        return $this;
    }

    /**
     * Gets middle_name
     * @return string
     */
    public function getMiddleName()
    {
        return $this->container['middle_name'];
    }

    /**
     * Sets middle_name
     * @param string $middle_name The shopper's middle name
     * @return $this
     */
    public function setMiddleName($middle_name)
    {
        $this->container['middle_name'] = $middle_name;

        return $this;
    }

    /**
     * Gets phone
     * @return string
     */
    public function getPhone()
    {
        return $this->container['phone'];
    }

    /**
     * Sets phone
     * @param string $phone The shopper's contact phone number
     * @return $this
     */
    public function setPhone($phone)
    {

        if (!is_null($phone) && (!preg_match("/^\\+?[\\d\\s]+$/", $phone))) {
            throw new \InvalidArgumentException("invalid value for $phone when calling Shopper., must conform to the pattern /^\\+?[\\d\\s]+$/.");
        }

        $this->container['phone'] = $phone;

        return $this;
    }

    /**
     * Gets email
     * @return string
     */
    public function getEmail()
    {
        return $this->container['email'];
    }

    /**
     * Sets email
     * @param string $email The shopper's email address
     * @return $this
     */
    public function setEmail($email)
    {
        $this->container['email'] = $email;

        return $this;
    }

    /**
     * Gets birth_date
     * @return \DateTime
     */
    public function getBirthDate()
    {
        return $this->container['birth_date'];
    }

    /**
     * Sets birth_date
     * @param \DateTime $birth_date The shopper's birth date in the form yyyy-mm-dd
     * @return $this
     */
    public function setBirthDate($birth_date)
    {
        $this->container['birth_date'] = $birth_date;

        return $this;
    }

    /**
     * Gets gender
     * @return string
     */
    public function getGender()
    {
        return $this->container['gender'];
    }

    /**
     * Sets gender
     * @param string $gender The shopper's gender
     * @return $this
     */
    public function setGender($gender)
    {
        $allowed_values = array('Male', 'Female', 'Other');
        if (!is_null($gender) && (!in_array($gender, $allowed_values))) {
            throw new \InvalidArgumentException("Invalid value for 'gender', must be one of 'Male', 'Female', 'Other'");
        }
        $this->container['gender'] = $gender;

        return $this;
    }

    /**
     * Gets statistics
     * @return \zipMoney\Model\ShopperStatistics
     */
    public function getStatistics()
    {
        return $this->container['statistics'];
    }

    /**
     * Sets statistics
     * @param \zipMoney\Model\ShopperStatistics $statistics
     * @return $this
     */
    public function setStatistics($statistics)
    {
        $this->container['statistics'] = $statistics;

        return $this;
    }

    /**
     * Gets billing_address
     * @return \zipMoney\Model\Address
     */
    public function getBillingAddress()
    {
        return $this->container['billing_address'];
    }

    /**
     * Sets billing_address
     * @param \zipMoney\Model\Address $billing_address
     * @return $this
     */
    public function setBillingAddress($billing_address)
    {
        $this->container['billing_address'] = $billing_address;

        return $this;
    }
    /**
     * Returns true if offset exists. False otherwise.
     * @param  integer $offset Offset
     * @return boolean
     */
    public function offsetExists($offset)
    {
        return isset($this->container[$offset]);
    }

    /**
     * Gets offset.
     * @param  integer $offset Offset
     * @return mixed
     */
    public function offsetGet($offset)
    {
        return isset($this->container[$offset]) ? $this->container[$offset] : null;
    }

    /**
     * Sets value based on offset.
     * @param  integer $offset Offset
     * @param  mixed   $value  Value to be set
     * @return void
     */
    public function offsetSet($offset, $value)
    {
        if (is_null($offset)) {
            $this->container[] = $value;
        } else {
            $this->container[$offset] = $value;
        }
    }

    /**
     * Unsets offset.
     * @param  integer $offset Offset
     * @return void
     */
    public function offsetUnset($offset)
    {
        unset($this->container[$offset]);
    }

    /**
     * Gets the string presentation of the object
     * @return string
     */
    public function __toString()
    {
        if (defined('JSON_PRETTY_PRINT')) { // use JSON pretty print
            return json_encode(\zipMoney\ObjectSerializer::sanitizeForSerialization($this), JSON_PRETTY_PRINT);
        }

        return json_encode(\zipMoney\ObjectSerializer::sanitizeForSerialization($this));
    }
}


<?php
/**
 * OrderItem
 *
 * @category Class
 * @package  zipMoney
 * @author   zipMoney Payments Pty Ltd
 * @link     https://github.com/zipMoney/merchantapi-php
 */

namespace zipMoney\Model;

use \ArrayAccess;

class OrderItem implements ArrayAccess
{
    const DISCRIMINATOR = 'subclass';

    /**
      * The original name of the model.
      * @var string
      */
    protected static $swaggerModelName = 'OrderItem';

    /**
      * Array of property to type mappings. Used for (de)serialization
      * @var string[]
      */
    protected static $zipTypes = array(
        'name' => 'string',
        'amount' => 'float',
        'reference' => 'string',
        'description' => 'string',
        'quantity' => 'float',
        'type' => 'string',
        'image_uri' => 'string',
        'item_uri' => 'string',
        'product_code' => 'string',
        'additional_details' => '\zipMoney\Model\OrderItemAdditionalDetails[]'
    );

    public static function zipTypes()
    {
        return self::$zipTypes;
    }

    /**
     * Array of attributes where the key is the local name, and the value is the original name
     * @var string[]
     */
    protected static $attributeMap = array(
        'name' => 'name',
        'amount' => 'amount',
        'reference' => 'reference',
        'description' => 'description',
        'quantity' => 'quantity',
        'type' => 'type',
        'image_uri' => 'image_uri',
        'item_uri' => 'item_uri',
        'product_code' => 'product_code',
        'additional_details' => 'additional_details'
    );

    /**
     * Array of attributes to setter functions (for deserialization of responses)
     * @var string[]
     */
    protected static $setters = array(
        'name' => 'setName',
        'amount' => 'setAmount',
        'reference' => 'setReference',
        'description' => 'setDescription',
        'quantity' => 'setQuantity',
        'type' => 'setType',
        'image_uri' => 'setImageUri',
        'item_uri' => 'setItemUri',
        'product_code' => 'setProductCode',
        'additional_details' => 'setAdditionalDetails'
    );

    /**
     * Array of attributes to getter functions (for serialization of requests)
     * @var string[]
     */
    protected static $getters = array(
        'name' => 'getName',
        'amount' => 'getAmount',
        'reference' => 'getReference',
        'description' => 'getDescription',
        'quantity' => 'getQuantity',
        'type' => 'getType',
        'image_uri' => 'getImageUri',
        'item_uri' => 'getItemUri',
        'product_code' => 'getProductCode',
        'additional_details' => 'getAdditionalDetails'
    );

    public static function attributeMap()
    {
        return self::$attributeMap;
    }

    public static function setters()
    {
        return self::$setters;
    }

    public static function getters()
    {
        return self::$getters;
    }

    const TYPE_SKU = 'sku';
    const TYPE_TAX = 'tax';
    const TYPE_SHIPPING = 'shipping';
    const TYPE_DISCOUNT = 'discount';
    const TYPE_STORE_CREDIT = 'store_credit';

    /**
     * Gets allowable values of the enum
     * @return string[]
     */
    public function getTypeAllowableValues()
    {
        return array(
            self::TYPE_SKU,
            self::TYPE_TAX,
            self::TYPE_SHIPPING,
            self::TYPE_DISCOUNT,
            self::TYPE_STORE_CREDIT,
        );
    }

    /**
     * Associative array for storing property values
     * @var mixed[]
     */
    protected $container = array();

    /**
     * Constructor
     * @param mixed[] $data Associated array of property values initializing the model
     */
    public function __construct(array $data = null)
    {
        $this->container['name'] = isset($data['name']) ? $data['name'] : null;
        $this->container['amount'] = isset($data['amount']) ? $data['amount'] : null;
        $this->container['reference'] = isset($data['reference']) ? $data['reference'] : null;
        $this->container['description'] = isset($data['description']) ? $data['description'] : null;
        $this->container['quantity'] = isset($data['quantity']) ? $data['quantity'] : null;
        $this->container['type'] = isset($data['type']) ? $data['type'] : null;
        $this->container['image_uri'] = isset($data['image_uri']) ? $data['image_uri'] : null;
        $this->container['item_uri'] = isset($data['item_uri']) ? $data['item_uri'] : null;
        $this->container['product_code'] = isset($data['product_code']) ? $data['product_code'] : null;
        $this->container['additional_details'] = isset($data['additional_details']) ? $data['additional_details'] : null;
    }

    /**
     * show all the invalid properties with reasons.
     *
     * @return array invalid properties with reasons
     */
    public function listInvalidProperties()
    {
        $invalid_properties = array();

        if ($this->container['name'] === null) {
            $invalid_properties[] = "'name' can't be null";
        }
        if ($this->container['amount'] === null) {
            $invalid_properties[] = "'amount' can't be null";
        }
        if (!is_null($this->container['quantity']) && ($this->container['quantity'] <= 0)) {
            $invalid_properties[] = "invalid value for 'quantity', must be bigger than 0.";
        }

        if ($this->container['type'] === null) {
            $invalid_properties[] = "'type' can't be null";
        }
        $allowed_values = array("sku", "tax", "shipping", "discount", "store_credit");
        if (!in_array($this->container['type'], $allowed_values)) {
            $invalid_properties[] = "invalid value for 'type', must be one of 'sku', 'tax', 'shipping', 'discount', 'store_credit'.";
        }

        if (!is_null($this->container['product_code']) && (strlen($this->container['product_code']) > 200)) {
            $invalid_properties[] = "invalid value for 'product_code', the character length must be smaller than or equal to 200.";
        }

        return $invalid_properties;
    }

    /**
     * validate all the properties in the model
     * return true if all passed
     *
     * @return bool True if all properties are valid
     */
    public function valid()
    {

        if ($this->container['name'] === null) {
            return false;
        }
        if ($this->container['amount'] === null) {
            return false;
        }
        if ($this->container['quantity'] <= 0) {
            return false;
        }
        if ($this->container['type'] === null) {
            return false;
        }
        $allowed_values = array("sku", "tax", "shipping", "discount", "store_credit");
        if (!in_array($this->container['type'], $allowed_values)) {
            return false;
        }
        if (strlen($this->container['product_code']) > 200) {
            return false;
        }
        return true;
    }

    /**
     * Gets name
     * @return string
     */
    public function getName()
    {
        return $this->container['name'];
    }

    /**
     * Sets name
     * @param string $name
     * @return $this
     */
    public function setName($name)
    {
        $this->container['name'] = $name;

        return $this;
    }

    /**
     * Gets amount
     * @return float
     */
    public function getAmount()
    {
        return $this->container['amount'];
    }

    /**
     * Sets amount
     * @param float $amount
     * @return $this
     */
    public function setAmount($amount)
    {
        $this->container['amount'] = $amount;

        return $this;
    }

    /**
     * Gets reference
     * @return string
     */
    public function getReference()
    {
        return $this->container['reference'];
    }

    /**
     * Sets reference
     * @param string $reference
     * @return $this
     */
    public function setReference($reference)
    {
        $this->container['reference'] = $reference;

        return $this;
    }

    /**
     * Gets description
     * @return string
     */
    public function getDescription()
    {
        return $this->container['description'];
    }

    /**
     * Sets description
     * @param string $description
     * @return $this
     */
    public function setDescription($description)
    {
        $this->container['description'] = $description;

        return $this;
    }

    /**
     * Gets quantity
     * @return float
     */
    public function getQuantity()
    {
        return $this->container['quantity'];
    }

    /**
     * Sets quantity
     * @param float $quantity
     * @return $this
     */
    public function setQuantity($quantity)
    {

        if (!is_null($quantity) && ($quantity <= 0)) {
            throw new \InvalidArgumentException('invalid value for $quantity when calling OrderItem., must be bigger than 0.');
        }

        $this->container['quantity'] = $quantity;

        return $this;
    }

    /**
     * Gets type
     * @return string
     */
    public function getType()
    {
        return $this->container['type'];
    }

    /**
     * Sets type
     * @param string $type
     * @return $this
     */
    public function setType($type)
    {
        $allowed_values = array('sku', 'tax', 'shipping', 'discount', 'store_credit');
        if ((!in_array($type, $allowed_values))) {
            throw new \InvalidArgumentException("Invalid value for 'type', must be one of 'sku', 'tax', 'shipping', 'discount', 'store_credit'");
        }
        $this->container['type'] = $type;

        return $this;
    }

    /**
     * Gets image_uri
     * @return string
     */
    public function getImageUri()
    {
        return $this->container['image_uri'];
    }

    /**
     * Sets image_uri
     * @param string $image_uri
     * @return $this
     */
    public function setImageUri($image_uri)
    {
        $this->container['image_uri'] = $image_uri;

        return $this;
    }

    /**
     * Gets item_uri
     * @return string
     */
    public function getItemUri()
    {
        return $this->container['item_uri'];
    }

    /**
     * Sets item_uri
     * @param string $item_uri
     * @return $this
     */
    public function setItemUri($item_uri)
    {
        $this->container['item_uri'] = $item_uri;

        return $this;
    }

    /**
     * Gets product_code
     * @return string
     */
    public function getProductCode()
    {
        return $this->container['product_code'];
    }

    /**
     * Sets product_code
     * @param string $product_code
     * @return $this
     */
    public function setProductCode($product_code)
    {
        if (!is_null($product_code) && (strlen($product_code) > 200)) {
            throw new \InvalidArgumentException('invalid length for $product_code when calling OrderItem., must be smaller than or equal to 200.');
        }

        $this->container['product_code'] = $product_code;

        return $this;
    }

    /**
     * Gets additional_details
     * @return \zipMoney\Model\OrderItemAdditionalDetails[]
     */
    public function getAdditionalDetails()
    {
        return $this->container['additional_details'];
    }

    /**
     * Sets additional_details
     * @param \zipMoney\Model\OrderItemAdditionalDetails[] $additional_details
     * @return $this
     */
    public function setAdditionalDetails($additional_details)
    {
        $this->container['additional_details'] = $additional_details;

        return $this;
    }
    /**
     * Returns true if offset exists. False otherwise.
     * @param  integer $offset Offset
     * @return boolean
     */
    public function offsetExists($offset)
    {
        return isset($this->container[$offset]);
    }

    /**
     * Gets offset.
     * @param  integer $offset Offset
     * @return mixed
     */
    public function offsetGet($offset)
    {
        return isset($this->container[$offset]) ? $this->container[$offset] : null;
    }

    /**
     * Sets value based on offset.
     * @param  integer $offset Offset
     * @param  mixed   $value  Value to be set
     * @return void
     */
    public function offsetSet($offset, $value)
    {
        if (is_null($offset)) {
            $this->container[] = $value;
        } else {
            $this->container[$offset] = $value;
        }
    }

    /**
     * Unsets offset.
     * @param  integer $offset Offset
     * @return void
     */
    public function offsetUnset($offset)
    {
        unset($this->container[$offset]);
    }

    /**
     * Gets the string presentation of the object
     * @return string
     */
    public function __toString()
    {
        if (defined('JSON_PRETTY_PRINT')) { // use JSON pretty print
            return json_encode(\zipMoney\ObjectSerializer::sanitizeForSerialization($this), JSON_PRETTY_PRINT);
        }

        return json_encode(\zipMoney\ObjectSerializer::sanitizeForSerialization($this));
    }
}