%PDF- %PDF-
Direktori : /home/lightco1/public_html/lightingrepublic.com.au/plugins/vmpayment/klarna/klarna/api/ |
Current File : /home/lightco1/public_html/lightingrepublic.com.au/plugins/vmpayment/klarna/klarna/api/klarna.php |
<?php defined('_JEXEC') or die('Restricted access'); /** * Copyright 2010 KLARNA AB. All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, are * permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, this list of * conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, this list * of conditions and the following disclaimer in the documentation and/or other materials * provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY KLARNA AB "AS IS" AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL KLARNA AB OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * The views and conclusions contained in the software and documentation are those of the * authors and should not be interpreted as representing official policies, either expressed * or implied, of KLARNA AB. * * @package KlarnaAPI */ /** * This API provides a way to integrate with Klarna's services over the XMLRPC protocol. * * All strings inputted need to be encoded with ISO-8859-1.<br> * In addition you need to decode HTML entities, if they exist.<br> * * For more information see our {@link http://integration.klarna.com/en/api/step-by-step step by step} guide. * * Dependencies:<br> * xmlrpc-3.0.0.beta/lib/xmlrpc.inc from {@link http://phpxmlrpc.sourceforge.net/}<br> * xmlrpc-3.0.0.beta/lib/xmlrpc_wrappers.inc from {@link http://phpxmlrpc.sourceforge.net/}<br> * * @package KlarnaAPI * @version 2.1.2 * @since 2011-09-13 * @link http://integration.klarna.com/ * @copyright Copyright (c) 2005-2011 Klarna AB (http://klarna.com) */ class Klarna { /** * Klarna PHP API version identifier. * * @ignore Do not show this in PHPDoc. * @var string */ protected $VERSION = 'php:api:2.1.2'; /** * Klarna protocol identifier. * * @ignore Do not show this in PHPDoc. * @var string */ protected $PROTO = '4.1'; /** * Flag to indicate use of the report server Candice. * * @var bool */ private static $candice = true; /** * URL/Address to the Candice server. * Port used is 80. * * @var string */ private static $c_addr = "clientstat.kreditor.se"; /** * Constants used with LIVE mode for the communications with Klarna. * * @var int */ const LIVE = 0; /** * URL/Address to the live Klarna Online server. * Port used is 443 for SSL and 80 without. * * @var string */ private static $live_addr = 'payment.klarna.com'; /** * Constants used with BETA mode for the communications with Klarna. * * @var int */ const BETA = 1; /** * URL/Address to the beta test Klarna Online server. * Port used is 443 for SSL and 80 without. * * @var string */ //private static $beta_addr = 'payment-beta.klarna.com'; private static $beta_addr = 'payment.testdrive.klarna.com'; /** * Indicates whether the communications is over SSL or not. * * @ignore Do not show this in PHPDoc. * @var bool */ protected $ssl = false; /** * An object of xmlrpc_client, used to communicate with Klarna. * * @link http://phpxmlrpc.sourceforge.net/ * * @ignore Do not show this in PHPDoc. * @var xmlrpc_client */ protected $xmlrpc; /** * Which server the Klarna API is using, LIVE or BETA (TESTING). * * @see Klarna::LIVE * @see Klarna::BETA * * @ignore Do not show this in PHPDoc. * @var int */ protected $mode; /** * The URL/Address used to communicate with Klarna. * * @ignore Do not show this in PHPDoc. * @var string */ protected $addr; /** * The port number used to communicate with Klarna. * * @ignore Do not show this in PHPDoc. * @var int */ protected $port; /** * The estore's identifier received from Klarna. * * @var int */ private $eid; /** * The estore's shared secret received from Klarna. * * <b>Note</b>:<br> * DO NOT SHARE THIS WITH ANYONE! * * @var string */ private $secret; /** * KlarnaCountry constant. * * @see KlarnaCountry * * @var int */ private $country; /** * KlarnaCurrency constant. * * @see KlarnaCurrency * * @var int */ private $currency; /** * KlarnaLanguage constant. * * @see KlarnaLanguage * * @var int */ private $language; /** * An array of articles for the current order. * * @ignore Do not show this in PHPDoc. * @var array */ protected $goodsList; /** * An array of article numbers and quantity. * * @ignore Do not show this in PHPDoc. * @var array */ protected $artNos; /** * An KlarnaAddr object containing the billing address. * * @ignore Do not show this in PHPDoc. * @var KlarnaAddr */ protected $billing; /** * An KlarnaAddr object containing the shipping address. * * @ignore Do not show this in PHPDoc. * @var KlarnaAddr */ protected $shipping; /** * Estore's user(name) or identifier. * Only used in {@link Klarna::addTransaction()}. * * @ignore Do not show this in PHPDoc. * @var string */ protected $estoreUser = ""; /** * External order numbers from other systems. * * @ignore Do not show this in PHPDoc. * @var string */ protected $orderid = array("", ""); /** * Reference (person) parameter. * * @ignore Do not show this in PHPDoc. * @var string */ protected $reference = ""; /** * Reference code parameter. * * @ignore Do not show this in PHPDoc. * @var string */ protected $reference_code = ""; /** * An array of named extra info. * * @ignore Do not show this in PHPDoc. * @var array */ protected $extraInfo = array(); /** * An array of named bank info. * * @ignore Do not show this in PHPDoc. * @var array */ protected $bankInfo = array(); /** * An array of named income expense info. * * @ignore Do not show this in PHPDoc. * @var array */ protected $incomeInfo = array(); /** * An array of named shipment info. * * @ignore Do not show this in PHPDoc. * @var array */ protected $shipInfo = array(); /** * An array of named travel info. * * @ignore Do not show this in PHPDoc. * @var array */ protected $travelInfo = array(); /** * An array of named session id's.<br> * E.g. "dev_id_1" => ...<br> * * @ignore Do not show this in PHPDoc. * @var array */ protected $sid = array(); /** * A comment sent in the XMLRPC communications. * This is resetted using clear(). * * @ignore Do not show this in PHPDoc. * @var string */ protected $comment = ""; /** * An array with all the checkoutHTML objects. * * @ignore Do not show this in PHPDoc. * @var array */ protected $coObjects = array(); /** * Flag to indicate if the API should output verbose * debugging information. * * @var bool */ public static $debug = false; /** * Turns on the internal XMLRPC debugging. * * @var bool */ public static $xmlrpcDebug = false; /** * If this is set to true, XMLRPC invocation is disabled. * * @var bool */ public static $disableXMLRPC = false; /** * If the estore is using a proxy which populates the clients IP to x_forwarded_for * then and only then should this be set to true. * * <b>Note</b>:<br> * USE WITH CARE! * * @var bool */ public static $x_forwarded_for = false; /** * Array of HTML entities, used to create numeric htmlentities. * * @ignore Do not show this in PHPDoc. * @var array */ protected static $htmlentities = false; /** * Populated with possible proxy information. * A comma separated list of IP addresses. * * @var string */ private $x_fwd; /** * The storage class for PClasses. * * Use 'xml' for xmlstorage.class.php.<br> * Use 'mysql' for mysqlstorage.class.php.<br> * Use 'json' for jsonstorage.class.php.<br> * * @ignore Do not show this in PHPDoc. * @var string */ protected $pcStorage; /** * The storage URI for PClasses. * * Use the absolute or relative URI to a file if {@link Klarna::$pcStorage} is set as 'xml' or 'json'.<br> * Use a HTTP-auth similar URL if {@link Klarna::$pcStorage} is set as 'mysql', <br> * e.g. user:passwd@addr:port/dbName.dbTable.<br> * * @ignore Do not show this in PHPDoc. * @var string */ protected $pcURI; /** * PCStorage instance. * * @ignore Do not show this in PHPDoc. * @var PCStorage */ protected $pclasses; /** * ArrayAccess instance. * * @ignore Do not show this in PHPDoc. * @var ArrayAccess */ protected $config; /** * Class constructor * * @ignore Does nothing... */ public function __construct() { } /** * Class destructor * * @ignore Does nothing... */ public function __destruct() { } /** * Checks if the config has fields described in argument.<br> * Missing field(s) is in the exception message. * * To check that the config has eid and secret:<br> * <code> * try { * $this->hasFields('eid', 'secret'); * } * catch(Exception $e) { * echo "Missing fields: " . $e->getMessage(); * } * </code> * * @ignore Do not show this in PHPDoc. * @param mixed $field1 Field name. * @param mixed $field2 Field name. * @param mixed $field3 Field name. * @param mixed ... Field name. * @throws Exception * @return void */ protected function hasFields(/*variable arguments*/) { $missingFields = array(); $args = func_get_args(); foreach($args as $field) { if(!isset($this->config[$field])) { $missingFields[] = $field; } } if(count($missingFields) > 0) { throw new Exception('Missing config field(s): ' . implode(', ', $missingFields), 50001); } } /** * Initializes the Klarna object accordingly to the set config object. * * @ignore Do not show this in PHPDoc. * @throws KlarnaException|Exception * @return void */ protected function init() { $this->hasFields( 'eid', 'secret', 'mode', 'pcStorage', 'pcURI' ); if(!is_int($this->config['eid'])) { $this->config['eid'] = intval($this->config['eid']); } if($this->config['eid'] <= 0) { throw new Exception("Config field 'eid' is not valid!", 50001); } if(!is_string($this->config['secret'])) { $this->config['secret'] = strval($this->config['secret']); } if(strlen($this->config['secret']) == 0) { throw new Exception("Config field 'secret' not set!", 50001); } //Set the shop id and secret. $this->eid = $this->config['eid']; $this->secret = $this->config['secret']; if(!is_numeric($this->config['country']) && strlen($this->config['country']) == 2) { $this->setCountry($this->config['country']); } else { //Set the country specific attributes. try { $this->hasFields('country', 'language', 'currency'); //If hasFields doesn't throw exception we can set them all. $this->setCountry($this->config['country']); $this->setLanguage($this->config['language']); $this->setCurrency($this->config['currency']); } catch(Exception $e) { //fields missing for country, language or currency $this->country = $this->language = $this->currency = null; } } //Set addr and port according to mode. $this->mode = (int)$this->config['mode']; if($this->mode === self::LIVE) { $this->addr = self::$live_addr; $this->ssl = true; } else { $this->addr = self::$beta_addr; $this->ssl = true; } try { $this->hasFields('ssl'); $this->ssl = (bool)$this->config['ssl']; } catch(Exception $e) { //No 'ssl' field ignore it... } if($this->ssl) { $this->port = 443; } else { $this->port = 80; } try { $this->hasFields('candice'); self::$candice = (bool)$this->config['candice']; } catch(Exception $e) { //No 'candice' field ignore it... } try { $this->hasFields('xmlrpcDebug'); Klarna::$xmlrpcDebug = $this->config['xmlrpcDebug']; } catch(Exception $e) { //No 'xmlrpcDebug' field ignore it... } try { $this->hasFields('debug'); Klarna::$debug = $this->config['debug']; } catch(Exception $e) { //No 'debug' field ignore it... } $this->pcStorage = $this->config['pcStorage']; $this->pcURI = $this->config['pcURI']; $this->xmlrpc = new xmlrpc_client('/', $this->addr, $this->port, (($this->ssl) ? 'https' : 'http')); $this->xmlrpc->request_charset_encoding = 'ISO-8859-1'; } /** * Method of ease for setting common config fields. * * The storage module for PClasses:<br> * Use 'xml' for xmlstorage.class.php.<br> * Use 'mysql' for mysqlstorage.class.php.<br> * Use 'json' for jsonstorage.class.php.<br> * * The storage URI for PClasses:<br> * Use the absolute or relative URI to a file if {@link Klarna::$pcStorage} is set as 'xml' or 'json'.<br> * Use a HTTP-auth similar URL if {@link Klarna::$pcStorage} is set as 'mysql', <br> * e.g. user:passwd@addr:port/dbName.dbTable.<br> * * <b>Note</b>:<br> * This disables the config file storage.<br> * * @see Klarna::setConfig() * @see KlarnaConfig * * @param int $eid Merchant ID/EID * @param string $secret Secret key/Shared key * @param int $country {@link KlarnaCountry} * @param int $language {@link KlarnaLanguage} * @param int $currency {@link KlarnaCurrency} * @param int $mode {@link Klarna::LIVE} or {@link Klarna::BETA} * @param string $pcStorage PClass storage module. * @param string $pcURI PClass URI. * @param bool $ssl Whether HTTPS (HTTP over SSL) or HTTP is used. * @param bool $candice Error reporting to Klarna. * @throws KlarnaException * @return void */ public function config($eid, $secret, $country, $language, $currency, $mode = Klarna::LIVE, $pcStorage = 'json', $pcURI = 'pclasses.json', $ssl = true, $candice = true) { try { KlarnaConfig::$store = false; $this->config = new KlarnaConfig(null); $this->config['eid'] = $eid; $this->config['secret'] = $secret; $this->config['country'] = $country; $this->config['language'] = $language; $this->config['currency'] = $currency; $this->config['mode'] = $mode; $this->config['ssl'] = $ssl; $this->config['candice'] = $candice; $this->config['pcStorage'] = $pcStorage; $this->config['pcURI'] = $pcURI; $this->init(); } catch(Exception $e) { $this->config = null; throw new KlarnaException('Error in ' . __METHOD__ . ': ' . $e->getMessage(), $e->getCode()); } } /** * Sets and initializes this Klarna object using the supplied config object. * * @see KlarnaConfig * @param KlarnaConfig &$config Config object. * @throws KlarnaException * @return void */ public function setConfig(&$config) { try { if($config instanceof ArrayAccess) { $this->config = $config; $this->init(); } else { throw new Exception('Supplied config is not a KlarnaConfig/ArrayAccess object!', 50001); } } catch(Exception $e) { $this->config = null; throw new KlarnaException('Error in ' . __METHOD__ . ': ' . $e->getMessage(), $e->getCode()); } } /** * Sets the country used. * * <b>Note</b>:<br> * If you input 'dk', 'fi', 'de', 'nl', 'no' or 'se', <br> * then currency and language will be set to mirror that country.<br> * * @see KlarnaCountry * * @param string|int $country {@link KlarnaCountry} * @throws KlarnaException * @return void */ public function setCountry($country) { if(!is_numeric($country) && (strlen($country) == 2 || strlen($country) == 3)) { $this->setCountry(self::getCountryForCode($country)); $this->setCurrency($this->getCurrencyForCountry()); $this->setLanguage($this->getLanguageForCountry()); } else { $this->checkCountry($country, __METHOD__); $this->country = $country; } } /** * Returns the country code for the set country constant. * * @param int {@link KlarnaCountry Country} constant. * @return string Two letter code, e.g. "se", "no", etc. */ public function getCountryCode($country = null) { $country = ($country === null) ? $this->country : $country; $code = KlarnaCountry::getCode($country); return ($code === null) ? '' : $code; } /** * Returns the {@link KlarnaCountry country} constant from the country code. * * @param string $code Two letter code, e.g. "se", "no", etc. * @throws KlarnaException * @return int {@link KlarnaCountry Country} constant. */ public static function getCountryForCode($code) { $country = KlarnaCountry::fromCode($code); if ($country === null) { throw new KlarnaException('Error in ' . __METHOD__ . ': Unknown country! ("'.$code.'")', 50002); } return $country; } /** * Returns the country constant. * * @return int {@link KlarnaCountry} */ public function getCountry() { return $this->country; } /** * Sets the language used. * * <b>Note</b>:<br> * You can use the two letter language code instead of the constant.<br> * E.g. 'da' instead of using {@link KlarnaLanguage::DA}.<br> * * @see KlarnaLanguage * * @param string|int $language {@link KlarnaLanguage} * @throws KlarnaException * @return void */ public function setLanguage($language) { if(!is_numeric($language) && strlen($language) == 2) { $this->setLanguage(self::getLanguageForCode($language)); } else { $this->checkLanguage($language, __METHOD__); $this->language = $language; } } /** * Returns the language code for the set language constant. * * @param int {@link KlarnaLanguage Language} constant. * @return string Two letter code, e.g. "da", "de", etc. */ public function getLanguageCode($language = null) { $language = ($language === null) ? $this->language : $language; $code = KlarnaLanguage::getCode($language); return ($code === null) ? '' : $code; } /** * Returns the {@link KlarnaLanguage language} constant from the language code. * * @param string $code Two letter code, e.g. "da", "de", etc. * @throws KlarnaException * @return int {@link KlarnaLanguage Language} constant. */ public static function getLanguageForCode($code) { $language = KlarnaLanguage::fromCode($code); if ($language === null) { throw new KlarnaException('Error in ' . __METHOD__ . ': Unknown language! ('.$code.')', 50003); } return $language; } /** * Returns the language constant. * * @return int {@link KlarnaLanguage} */ public function getLanguage() { return $this->language; } /** * Sets the currency used. * * <b>Note</b>:<br> * You can use the three letter shortening of the currency.<br> * E.g. "dkk", "eur", "nok" or "sek" instead of the constant.<br> * * @see KlarnaCurrency * * @param string|int $currency {@link KlarnaCurrency} * @throws KlarnaException * @return void */ public function setCurrency($currency) { if(!is_numeric($currency) && strlen($currency) == 3) { $this->setCurrency(self::getCurrencyForCode($currency)); } else { $this->checkCurrency($currency, __METHOD__); $this->currency = $currency; } } /** * Returns the {@link KlarnaCurrency currency} constant from the currency code. * * @param string $code Two letter code, e.g. "dkk", "eur", etc. * @throws KlarnaException * @return int {@link KlarnaCurrency Currency} constant. */ public static function getCurrencyForCode($code) { $currency = KlarnaCurrency::fromCode($code); if ($code === null) { throw new KlarnaException('Error in ' . __METHOD__ . ': Unknown currency! ('.$code.')', 50004); } return $currency; } /** * Returns the the currency code for the set currency constant. * * @param int {@link KlarnaCurrency Currency} constant. * @return string Three letter currency code. */ public function getCurrencyCode($currency = null) { $currency = ($currency === null) ? $this->currency : $currency; $code = KlarnaCurrency::getCode($currency); return ($code === null) ? '' : $code; } /** * Returns the set currency constant. * * @return int {@link KlarnaCurrency} */ public function getCurrency() { return $this->currency; } /** * Checks set country against set currency and returns true if they match.<br> * {@link KlarnaCountry} or {@link KlarnaCurrency} constants can be used, or letter codes.<br> * Uses set values if parameter is null.<br> * * E.g. Klarna allows Euro with Germany, Netherlands and Finland, thus true will be returned. * * @param string|int $country {@link KlarnaCountry} * @param string|int $currency {@link KlarnaCurrency} * @throws KlarnaException * @return bool */ public function checkCountryCurrency($country = null, $currency = null) { if($country === null) { $country = $this->country; } else { if(!is_numeric($country) && (strlen($country) == 2 || strlen($country) == 3)) { $country = self::getCountryForCode($country); } } if($currency === null) { $currency = $this->currency; } else { if(!is_numeric($currency) && strlen($currency) == 3) { $currency = self::getCurrencyForCode($currency); } } switch($country) { case KlarnaCountry::DE: case KlarnaCountry::NL: case KlarnaCountry::FI: return ($currency !== KlarnaCurrency::EUR) ? false : true; case KlarnaCountry::DK: return ($currency !== KlarnaCurrency::DKK) ? false : true; case KlarnaCountry::NO: return ($currency !== KlarnaCurrency::NOK) ? false : true; case KlarnaCountry::SE: return ($currency !== KlarnaCurrency::SEK) ? false : true; default: //Country not yet supported by Klarna. return false; } } /** * Returns the {@link KlarnaLanguage language} constant for the specified or set country. * * @param int $country {@link KlarnaCountry Country} constant. * @return mixed False, if no match otherwise {@link KlarnaLanguage language} constant. */ public function getLanguageForCountry($country = null) { $country = ($country === null) ? $this->country : $country; switch($country) { case KlarnaCountry::DE: return KlarnaLanguage::DE; case KlarnaCountry::NL: return KlarnaLanguage::NL; case KlarnaCountry::FI: return KlarnaLanguage::FI; case KlarnaCountry::DK: return KlarnaLanguage::DA; case KlarnaCountry::NO: return KlarnaLanguage::NB; case KlarnaCountry::SE: return KlarnaLanguage::SV; default: //Country not yet supported by Klarna. return false; } } /** * Returns the {@link KlarnaCurrency currency} constant for the specified or set country. * * @param int $country {@link KlarnaCountry country} constant. * @return mixed False, if no match otherwise {@link KlarnaCurrency currency} constant. */ public function getCurrencyForCountry($country = null) { $country = ($country === null) ? $this->country : $country; switch($country) { case KlarnaCountry::DE: case KlarnaCountry::NL: case KlarnaCountry::FI: return KlarnaCurrency::EUR; case KlarnaCountry::DK: return KlarnaCurrency::DKK; case KlarnaCountry::NO: return KlarnaCurrency::NOK; case KlarnaCountry::SE: return KlarnaCurrency::SEK; default: //Country not yet supported by Klarna. return false; } } /** * <b>STILL UNDER DEVELOPMENT</b><br> * Sets the session id's for various device identification, * behaviour identification software. * * <b>Available named session id's</b>:<br> * string - dev_id_1<br> * string - dev_id_2<br> * string - dev_id_3<br> * string - beh_id_1<br> * string - beh_id_2<br> * string - beh_id_3<br> * * @param string $name Session ID identifier, e.g. 'dev_id_1'. * @param string $sid Session ID. * @throws KlarnaException * @return void */ public function setSessionID($name, $sid) { try { if(!is_string($name)) { $name = strval($name); } if(strlen($name) == 0) { throw new Exception("Argument 'name' is not set!", 50005); } if(!is_string($sid)) { $sid = strval($sid); } if(strlen($sid) == 0) { throw new Exception("Argument 'sid' is not set!", 50006); } if(!is_array($this->sid)) { $this->sid = array(); } $this->sid[$name] = $sid; } catch(Exception $e) { throw new KlarnaException("Error in " . __METHOD__ . ": " .$e->getMessage(), $e->getCode()); } } /** * <b>STILL UNDER DEVELOPMENT</b><br> * Sets the shipment information for the upcoming transaction.<br> * * Using this method is optional. * * <b>Available named values are</b>:<br> * int - delay_adjust<br> * string - shipping_company<br> * string - shipping_product<br> * string - tracking_no<br> * array - warehouse_addr<br> * * "warehouse_addr" is sent using {@link KlarnaAddr::toArray()}. * * Make sure you send in the values as the right data type.<br> * Use strval, intval or similar methods to ensure the right type is sent.<br> * * @param string $name * @param mixed $value * @throws KlarnaException * @return void */ public function setShipmentInfo($name, $value) { try { if(!is_string($name)) { $name = strval($name); } if(strlen($name) == 0) { throw new Exception("Argument 'name' is not set!", 50005); } if(!is_array($this->shipInfo)) { $this->shipInfo = array(); } $this->shipInfo[$name] = $value; } catch(Exception $e) { throw new KlarnaException("Error in " . __METHOD__ . ": " .$e->getMessage(), $e->getCode()); } } /** * <b>STILL UNDER DEVELOPMENT</b><br> * Sets the extra information for the upcoming transaction.<br> * * Using this method is optional. * * <b>Available named values are</b>:<br> * string - cust_no<br> * string - estore_user<br> * string - maiden_name<br> * string - place_of_birth<br> * string - password<br> * string - new_password<br> * string - captcha<br> * int - poa_group<br> * string - poa_pno<br> * string - ready_date<br> * string - rand_string<br> * int - bclass<br> * string - pin<br> * * Make sure you send in the values as the right data type.<br> * Use strval, intval or similar methods to ensure the right type is sent.<br> * * @param string $name * @param mixed $value * @throws KlarnaException * @return void */ public function setExtraInfo($name, $value) { try { if(!is_string($name)) { $name = strval($name); } if(strlen($name) == 0) { throw new Exception("Argument 'name' is not set!", 50005); } if(!is_array($this->extraInfo)) { $this->extraInfo = array(); } $this->extraInfo[$name] = $value; } catch(Exception $e) { throw new KlarnaException("Error in " . __METHOD__ . ": " .$e->getMessage(), $e->getCode()); } } /** * <b>STILL UNDER DEVELOPMENT</b><br> * Sets the income expense information for the upcoming transaction.<br> * * Using this method is optional. * * <b>Available named values are</b>:<br> * int - yearly_salary<br> * int - no_people_in_household<br> * int - no_children_below_18<br> * int - net_monthly_household_income<br> * int - monthly_cost_accommodation<br> * int - monthly_cost_other_loans<br> * * Make sure you send in the values as the right data type.<br> * Use strval, intval or similar methods to ensure the right type is sent.<br> * * @param string $name * @param mixed $value * @throws KlarnaException * @return void */ public function setIncomeInfo($name, $value) { try { if(!is_string($name)) { $name = strval($name); } if(strlen($name) == 0) { throw new Exception("Argument 'name' is not set!", 50005); } if(!is_array($this->incomeInfo)) { $this->incomeInfo = array(); } $this->incomeInfo[$name] = $value; } catch(Exception $e) { throw new KlarnaException("Error in " . __METHOD__ . ": " .$e->getMessage(), $e->getCode()); } } /** * <b>STILL UNDER DEVELOPMENT</b><br> * Sets the bank information for the upcoming transaction.<br> * * Using this method is optional. * * <b>Available named values are</b>:<br> * int - bank_acc_bic<br> * int - bank_acc_no<br> * int - bank_acc_pin<br> * int - bank_acc_tan<br> * string - bank_name<br> * string - bank_city<br> * string - iban<br> * * Make sure you send in the values as the right data type.<br> * Use strval, intval or similar methods to ensure the right type is sent.<br> * * @param string $name * @param mixed $value * @throws KlarnaException * @return void */ public function setBankInfo($name, $value) { try { if(!is_string($name)) { $name = strval($name); } if(strlen($name) == 0) { throw new Exception("Argument 'name' is not set!", 50005); } if(!is_array($this->bankInfo)) { $this->bankInfo = array(); } $this->bankInfo[$name] = $value; } catch(Exception $e) { throw new KlarnaException("Error in " . __METHOD__ . ": " .$e->getMessage(), $e->getCode()); } } /** * <b>STILL UNDER DEVELOPMENT</b><br> * Sets the travel information for the upcoming transaction.<br> * * Using this method is optional. * * <b>Available named values are</b>:<br> * string - travel_company<br> * string - reseller_company<br> * string - departure_date<br> * string - return_date<br> * array - destinations<br> * array - passenger_list<br> * array - passport_no<br> * array - driver_license_no<br> * * Make sure you send in the values as the right data type.<br> * Use strval, intval or similar methods to ensure the right type is sent.<br> * * @param string $name * @param mixed $value * @throws KlarnaException * @return void */ public function setTravelInfo($name, $value) { try { if(!is_string($name)) { $name = strval($name); } if(strlen($name) == 0) { throw new Exception("Argument 'name' is not set!", 50005); } if(!is_array($this->travelInfo)) { $this->travelInfo = array(); } $this->travelInfo[$name] = $value; } catch(Exception $e) { throw new KlarnaException("Error in " . __METHOD__ . ": " .$e->getMessage(), $e->getCode()); } } /** * Returns the clients IP address. * * @return string */ public function getClientIP() { //Proxy handling. $tmp_ip = $_SERVER['REMOTE_ADDR']; $x_fwd = isset($_SERVER["HTTP_X_FORWARDED_FOR"]) ? $_SERVER["HTTP_X_FORWARDED_FOR"] : null; if(self::$x_forwarded_for && $x_fwd !== null) { //Cut out the first IP address if(($cpos = strpos($x_fwd, ',')) !== false) { $tmp_ip = substr($x_fwd, 0, $cpos); $x_fwd = substr($x_fwd, $cpos+2); } else { //Only one IP address $tmp_ip = $x_fwd; $x_fwd = null; } } $this->x_fwd = $x_fwd; return $tmp_ip; } /** * Sets the specified address for the current order. * * <b>Address type can be</b>:<br> * {@link KlarnaFlags::IS_SHIPPING}<br> * {@link KlarnaFlags::IS_BILLING}<br> * * @param int $type Address type. * @param KlarnaAddr $addr Specified address. * @throws KlarnaException * @return void */ public function setAddress($type, $addr) { if(!($addr instanceof KlarnaAddr)) { throw new KlarnaException('Error in ' . __METHOD__ . ': Supplied address is not a KlarnaAddr object!', 50011); } if($addr->isCompany === null) { $addr->isCompany = false; } if($type === KlarnaFlags::IS_SHIPPING) { $this->shipping = $addr; self::printDebug("shipping address array", $this->shipping); } else if($type === KlarnaFlags::IS_BILLING) { $this->billing = $addr; self::printDebug("billing address array", $this->billing); } else { throw new KlarnaException("Error in " . __METHOD__ . ": Unknown address type ($type)", 50012); } } /** * Sets order id's from other systems for the upcoming transaction.<br> * User is only sent with {@link Klarna::addTransaction()}.<br> * * @see Klarna::setExtraInfo() * @param string $orderid1 * @param string $orderid2 * @param string $user * @throws KlarnaException * @return void */ public function setEstoreInfo($orderid1 = "", $orderid2 = "", $user = "") { if(!is_string($user)) { $user = strval($user); } if(!is_string($orderid1)) { $orderid1 = strval($orderid1); } if(!is_string($orderid2)) { $orderid2 = strval($orderid2); } if(!is_string($user)) { $user = strval($user); } if(strlen($user) > 0 ) { $this->setExtraInfo('estore_user', $user); } $this->orderid[0] = $orderid1; $this->orderid[1] = $orderid2; } /** * Sets the reference (person) and reference code, for the upcoming transaction. * * If this is omitted, it can grab first name, last name from the address and use that as a reference person. * * @param string $ref Reference person / message to customer on invoice. * @param string $code Reference code / message to customer on invoice. * @return void */ public function setReference($ref, $code) { $this->checkRef($ref, $code, __METHOD__); $this->reference = $ref; $this->reference_code = $code; } /** * Returns the reference (person). * * @return string */ public function getReference() { return $this->reference; } /** * Returns an associative array used to send the address to Klarna. * * @ignore Do not show this in PHPDoc. * @param string $method __METHOD__, the method calling assembleAddr. * @param KlarnaAddr $addr Address object to assemble. * @throws KlarnaException * @return array The address for the specified method. */ protected function assembleAddr($method, $addr) { if(!($addr instanceof KlarnaAddr)) { throw new KlarnaException('Error in ' . $method . ': Specified address is not a KlarnaAddr object! (Call setAddress first?!)', 50013); } $tmp = $addr->toArray(); //Check address! if($tmp['country'] === KlarnaCountry::NL || $tmp['country'] === KlarnaCountry::DE) { if(strlen($tmp['house_number']) == 0) { throw new KlarnaException("Error in " . $method . ': House number needs to be specified for Netherlands and Germany!', 50014); } } if(strlen($tmp['email']) == 0) { throw new KlarnaException("Error in " . $method . ': Email address not set!', 50015); } //Check email against a regular expression. if(!preg_match("/^[_a-zA-Z0-9-]+(\.[_a-zA-Z0-9-]+)*@[a-zA-Z0-9-]+(\.[a-zA-Z0-9-]+)*(\.[a-zA-Z0-9-][a-zA-Z0-9-]+)+$/", $tmp['email'])) { throw new KlarnaException("Error in " . $method . ': Email address is not valid! ('.$tmp['email'].')', 50016); } //Only check fname and lname if company isn't set. if(strlen($tmp['company']) == 0) { if(strlen($tmp['fname']) == 0) { throw new KlarnaException("Error in " . $method . ': First name not set!', 50017); } if(strlen($tmp['lname']) == 0) { throw new KlarnaException("Error in " . $method . ': Last name not set!', 50018); } } if(strlen($tmp['street']) == 0) { throw new KlarnaException("Error in " . $method . ': Street address not set!', 50019); } if(strlen($tmp['zip']) == 0) { throw new KlarnaException("Error in " . $method . ': Zip code not set!', 50020); } if(strlen($tmp['city']) == 0) { throw new KlarnaException("Error in " . $method . ': City not set!', 50021); } if($tmp['country'] <= 0) { throw new KlarnaException("Error in " . $method . ': Country not set!', 50022); } return $tmp; } /** * Sets the comment field, which can be shown in the invoice. * * @param string $data * @return void */ public function setComment($data) { $this->comment = $data; } /** * Adds an additional comment to the comment field. * * @see Klarna::setComment() * * @param string $data * @return void */ public function addComment($data) { $this->comment .= "\n".$data; } /** * Returns the PNO/SSN encoding constant for currently set country. * * <b>Note</b>:<br> * Country, language and currency needs to match! * * @throws KlarnaException * @return int {@link KlarnaEncoding} constant. */ public function getPNOEncoding() { if(!is_int($this->country) || !is_int($this->language) || !is_int($this->currency)) { throw new KlarnaException('Error in ' . __METHOD__ . ': You must set country, language and currency!', 50023); } switch($this->country) { case KlarnaCountry::DE: if($this->currency !== KlarnaCurrency::EUR || $this->language !== KlarnaLanguage::DE) { throw new KlarnaException('Error in ' . __METHOD__ . ': Mismatching currency/language for DE! ('.$this->currency.','.$this->language.')', 50024); } return KlarnaEncoding::PNO_DE; break; case KlarnaCountry::DK: if($this->currency !== KlarnaCurrency::DKK || $this->language !== KlarnaLanguage::DA) { throw new KlarnaException('Error in ' . __METHOD__ . ': Mismatching currency/language for DK! ('.$this->currency.','.$this->language.')', 50024); } return KlarnaEncoding::PNO_DK; break; case KlarnaCountry::FI: if($this->currency !== KlarnaCurrency::EUR || ($this->language !== KlarnaLanguage::FI && $this->language !== KlarnaLanguage::SV)) { throw new KlarnaException('Error in ' . __METHOD__ . ': Mismatching currency/language for FI! ('.$this->currency.','.$this->language.')', 50024); } return KlarnaEncoding::PNO_FI; break; case KlarnaCountry::NL: if($this->currency !== KlarnaCurrency::EUR || $this->language !== KlarnaLanguage::NL) { throw new KlarnaException('Error in ' . __METHOD__ . ': Mismatching currency/language for NL! ('.$this->currency.','.$this->language.')', 50024); } return KlarnaEncoding::PNO_NL; break; case KlarnaCountry::NO: if($this->currency !== KlarnaCurrency::NOK || $this->language !== KlarnaLanguage::NB) { throw new KlarnaException('Error in ' . __METHOD__ . ': Mismatching currency/language for NO! ('.$this->currency.','.$this->language.')', 50024); } return KlarnaEncoding::PNO_NO; break; case KlarnaCountry::SE: if($this->currency !== KlarnaCurrency::SEK || $this->language !== KlarnaLanguage::SV) { throw new KlarnaException('Error in ' . __METHOD__ . ': Mismatching currency/language for SE ('.$this->currency.','.$this->language.')', 50024); } return KlarnaEncoding::PNO_SE; break; default: throw new KlarnaException('Error in ' . __METHOD__ . ': Unknown/unsupported country! (ISO3166 '.$this->country.')', 50025); } } /** * The purpose of this method is to check if the customer has answered the ILT questions.<br> * If the questions need to be answered, an array will be returned where the key is the<br> * corresponding identifier for {@link Klarna::setIncomeInfo()}, which contains the question,<br> * the input type and the values.<br> * * Note: * You need to call {@link Klarna::setAddress()} with {@link KlarnaFlags::IS_SHIPPING} before calling this method. * * An example could be:<br> * <code> * array( * 'children_under_18' => array( * 'text' => 'Aantal kinderen onder de 18 jaar die thuiswonen?', * 'type' => 'drop-down', * 'values' => array('0','1','2','3','4','>5') * ) * ) * </code> * * You need to render this question and then send the identifier<br> * and the user supplied answer in {@link Klarna::setIncomeInfo()}. * * @param int|float $amount Amount including VAT. * @param string $pno Personal number, SSN, date of birth, etc. * @param int $gender {@link KlarnaFlags::FEMALE} or {@link KlarnaFlags::MALE}, null or "" for unspecified. * @param int $encoding {@link KlarnaEncoding Encoding} constant for the PNO parameter. * @throws KlarnaException * @return array */ public function checkILT($amount, $pno, $gender, $encoding = null) { if(!is_int($this->country) || !is_int($this->language) || !is_int($this->currency)) { throw new KlarnaException('Error in ' . __METHOD__ . ': You must set country, language and currency! ('.$this->country.','.$this->currency.','.$this->language.')', 50023); } $this->checkAmount($amount, __METHOD__); //Get the PNO/SSN encoding constant. $encoding = ($encoding === null) ? $this->getPNOEncoding() : $encoding; $this->checkPNO($pno, $encoding, __METHOD__); if($gender === 'm') { $gender = KlarnaFlags::MALE; } else if($gender === 'f') { $gender = KlarnaFlags::FEMALE; } if($gender !== null) { $this->checkInt($gender, 'gender', __METHOD__); } if(!($this->shipping instanceof KlarnaAddr)) { throw new KlarnaException("Error in " . __METHOD__ . ": No shipping address set!", 50035); } $shipping = $this->assembleAddr(__METHOD__, $this->shipping); //Shipping country must match specified country! if($shipping['country'] !== $this->country) { throw new KlarnaException('Error in ' . __METHOD__ . ': Shipping address country must match the country set!', 50036); } $digestSecret = self::digest($this->colon($this->eid, $pno, $this->secret)); $paramList = array($this->eid, $digestSecret, $amount, $pno, $gender, $shipping, $this->country, $this->language, $this->currency, $encoding); self::printDebug("check_ilt array", $paramList); $result = $this->xmlrpc_call('check_ilt', $paramList); self::printDebug("check_ilt result array", $result); return $result; } /** * Purpose: The get_addresses function is used to retrieve a customer's address(es).<br> * Using this, the customer is not required to enter any information only confirm the one presented to him/her.<br> * * The get_addresses function can also be used for companies.<br> * If the customer enters a company number, it will return all the addresses where the company is registered at.<br> * * The get_addresses function is ONLY allowed to be used for Swedish persons with the following conditions: * <ul> * <li>It can be only used if invoice or part payment is the default payment method</li> * <li>It has to disappear if the customer chooses another payment method</li> * <li>The button is not allowed to be called "get address", but "continue" or<br> * it can be picked up automatically when all the numbers have been typed.</li> * </ul> * * <b>Type can be one of these</b>:<br> * {@link KlarnaFlags::GA_ALL},<br> * {@link KlarnaFlags::GA_LAST},<br> * {@link KlarnaFlags::GA_GIVEN}.<br> * * @link http://integration.klarna.com/en/api/standard-integration/functions/getaddresses * @param string $pno Social security number, personal number, ... * @param int $encoding {@link KlarnaEncoding PNO Encoding} constant. * @param int $type Specifies returned information. * @throws KlarnaException * @return array An array of {@link KlarnaAddr} objects. */ public function getAddresses($pno, $encoding = null, $type = KlarnaFlags::GA_GIVEN) { if($this->country !== KlarnaCountry::SE) { throw new KlarnaException("Error in " . __METHOD__ . ": This method is only available for Swedish customers!", 50025); } //Get the PNO/SSN encoding constant. $encoding = ($encoding === null) ? $this->getPNOEncoding() : $encoding; $this->checkPNO($pno, $encoding, __METHOD__); $digestSecret = self::digest($this->colon($this->eid, $pno, $this->secret)); $paramList = array($pno, $this->eid, $digestSecret, $encoding, $type, $this->getClientIP()); self::printDebug("get_addresses array", $paramList); $result = $this->xmlrpc_call('get_addresses', $paramList); self::printDebug("get_addresses result array", $result); $addrs = array(); foreach($result as $tmpAddr) { try { $addr = new KlarnaAddr(); if($type === KlarnaFlags::GA_GIVEN) { $addr->isCompany = (count($tmpAddr) == 5) ? true : false; if($addr->isCompany) { $addr->setCompanyName($tmpAddr[0]); $addr->setStreet($tmpAddr[1]); $addr->setZipCode($tmpAddr[2]); $addr->setCity($tmpAddr[3]); $addr->setCountry($tmpAddr[4]); } else { $addr->setFirstName($tmpAddr[0]); $addr->setLastName($tmpAddr[1]); $addr->setStreet($tmpAddr[2]); $addr->setZipCode($tmpAddr[3]); $addr->setCity($tmpAddr[4]); $addr->setCountry($tmpAddr[5]); } } else if($type === KlarnaFlags::GA_LAST) { //Here we cannot decide if it is a company or not? Assume private person. $addr->setLastName($tmpAddr[0]); $addr->setStreet($tmpAddr[1]); $addr->setZipCode($tmpAddr[2]); $addr->setCity($tmpAddr[3]); $addr->setCountry($tmpAddr[4]); } else if($type === KlarnaFlags::GA_ALL) { if(strlen($tmpAddr[0]) > 0) { $addr->setFirstName($tmpAddr[0]); $addr->setLastName($tmpAddr[1]); } else { $addr->isCompany = true; $addr->setCompanyName($tmpAddr[1]); } $addr->setStreet($tmpAddr[2]); $addr->setZipCode($tmpAddr[3]); $addr->setCity($tmpAddr[4]); $addr->setCountry($tmpAddr[5]); } else { continue; } $addrs[] = $addr; } catch(Exception $e) { //Silently fail } } return $addrs; } /** * Adds an article to the current goods list for the current order. * * <b>Note</b>:<br> * It is recommended that you use {@link KlarnaFlags::INC_VAT}.<br> * * <b>Flags can be</b>:<br> * {@link KlarnaFlags::INC_VAT}<br> * {@link KlarnaFlags::IS_SHIPMENT}<br> * {@link KlarnaFlags::IS_HANDLING}<br> * {@link KlarnaFlags::PRINT_1000}<br> * {@link KlarnaFlags::PRINT_100}<br> * {@link KlarnaFlags::PRINT_10}<br> * {@link KlarnaFlags::NO_FLAG}<br> * * Some flags can be added to each other for multiple options. * * @see Klarna::addTransaction() * @see Klarna::reserveAmount() * @see Klarna::activateReservation() * * @param int $qty Quantity. * @param string $artNo Article number. * @param string $title Article title. * @param int $price Article price. * @param float $vat VAT in percent, e.g. 25% is inputted as 25. * @param float $discount Possible discount on article. * @param int $flags Options which specify the article ({@link KlarnaFlags::IS_HANDLING}) and it's price ({@link KlarnaFlags::INC_VAT}) * @throws KlarnaException * @return void */ public function addArticle($qty, $artNo, $title, $price, $vat, $discount = 0, $flags = KlarnaFlags::INC_VAT) { $this->checkQty($qty, __METHOD__); $prevException = false; try { $this->checkArtNo($artNo, __METHOD__); } catch(KlarnaException $e) { $prevException = $e; } try { $this->checkArtTitle($title, __METHOD__); } catch(KlarnaException $e) { if($prevException instanceof KlarnaException) { throw new KlarnaException('Error in ' . __METHOD__ . ': Title or ArtNo needs to be set!', 50026); } } $this->checkPrice($price, __METHOD__); $this->checkVAT($vat, __METHOD__); $this->checkDiscount($discount, __METHOD__); $this->checkInt($flags, 'flags', __METHOD__); //Create goodsList array if not set. if(!$this->goodsList || !is_array($this->goodsList)) { $this->goodsList = array(); } /*if(KlarnaFlags::PRINT_10 & $flags) { }*/ //Populate a temp array with the article details. $tmpArr = array( "artno" => $artNo, "title" => $title, "price" => $price, "vat" => $vat, "discount" => $discount, "flags" => $flags ); //Add the temp array and quantity field to the internal goods list. $this->goodsList[] = array( "goods" => $tmpArr, "qty" => $qty ); if(count($this->goodsList) > 0) { self::printDebug("article added", $this->goodsList[count($this->goodsList)-1]); } } /** * Assembles and sends the current order to Klarna.<br> * This clears all relevant data if $clear is set to true.<br> * * <b>This method returns an array with</b>:<br> * Invoice number<br> * Order status flag<br> * * If the flag {@link KlarnaFlags::RETURN_OCR} is used:<br> * Invoice number<br> * OCR number <br> * Order status flag<br> * * <b>Order status can be</b>:<br> * {@link KlarnaFlags::ACCEPTED}<br> * {@link KlarnaFlags::PENDING}<br> * {@link KlarnaFlags::DENIED}<br> * * Gender is only required for Germany and Netherlands.<br> * * <b>Flags can be</b>:<br> * {@link KlarnaFlags::NO_FLAG}<br> * {@link KlarnaFlags::TEST_MODE}<br> * {@link KlarnaFlags::AUTO_ACTIVATE}<br> * {@link KlarnaFlags::PRE_PAY}<br> * {@link KlarnaFlags::SENSITIVE_ORDER}<br> * {@link KlarnaFlags::RETURN_OCR}<br> * {@link KlarnaFlags::M_PHONE_TRANSACTION}<br> * {@link KlarnaFlags::M_SEND_PHONE_PIN}<br> * * Some flags can be added to each other for multiple options. * * <b>Note</b>:<br> * Normal shipment type is assumed unless otherwise specified, you can do this by calling:<br> * {@link Klarna::setShipmentInfo() Klarna::setShipmentInfo('delay_adjust', ...)}<br> * with either:<br> * {@link KlarnaFlags::NORMAL_SHIPMENT NORMAL_SHIPMENT} or {@link KlarnaFlags::EXPRESS_SHIPMENT EXPRESS_SHIPMENT}<br> * * @link http://integration.klarna.com/en/api/standard-integration/functions/addtransaction * @param string $pno Personal number, SSN, date of birth, etc. * @param int $gender {@link KlarnaFlags::FEMALE} or {@link KlarnaFlags::MALE}, null or "" for unspecified. * @param int $flags Options which affect the behaviour. * @param int $pclass PClass id used for this invoice. * @param int $encoding {@link KlarnaEncoding Encoding} constant for the PNO parameter. * @param bool $clear Whether customer info should be cleared after this call. * @throws KlarnaException * @return array An array with invoice number and order status. [string, int] */ public function addTransaction($pno, $gender, $flags = KlarnaFlags::NO_FLAG, $pclass = KlarnaPClass::INVOICE, $encoding = null, $clear = true) { if(!is_int($this->country) || !is_int($this->language) || !is_int($this->currency)) { throw new KlarnaException('Error in ' . __METHOD__ . ': You must set country, language and currency! ('.$this->country.','.$this->currency.','.$this->language.')', 50023); } $encoding = ($encoding === null) ? $this->getPNOEncoding() : $encoding; $this->checkPNO($pno, $encoding, __METHOD__); if($gender === 'm') { $gender = KlarnaFlags::MALE; } else if($gender === 'f') { $gender = KlarnaFlags::FEMALE; } if($gender !== null) { $this->checkInt($gender, 'gender', __METHOD__); } $this->checkInt($flags, 'flags', __METHOD__); $this->checkInt($pclass, 'pclass', __METHOD__); //Check so required information is set. if(!is_array($this->goodsList) || empty($this->goodsList)) { throw new KlarnaException("Error in " . __METHOD__ . ": No articles in goods list!", 50034); } //If only one address is set, copy to the other address. if(!($this->shipping instanceof KlarnaAddr) && ($this->billing instanceof KlarnaAddr)) { $this->shipping = $this->billing; } else if(!($this->billing instanceof KlarnaAddr) && ($this->shipping instanceof KlarnaAddr)) { $this->billing = $this->shipping; } else if(!($this->billing instanceof KlarnaAddr) && !($this->shipping instanceof KlarnaAddr)) { throw new KlarnaException("Error in " . __METHOD__ . ": No address set!", 50035); } //Assume normal shipment unless otherwise specified. if(!isset($this->shipInfo['delay_adjust'])) { $this->setShipmentInfo('delay_adjust', KlarnaFlags::NORMAL_SHIPMENT); } //Make sure we get any session ID's or similar $this->initCheckout(); //function add_transaction_digest $string = ""; foreach($this->goodsList as $goods) { $string .= $goods['goods']['title'] .':'; } $digestSecret = self::digest($string . $this->secret); //end function add_transaction_digest $billing = $this->assembleAddr(__METHOD__, $this->billing); $shipping = $this->assembleAddr(__METHOD__, $this->shipping); //Shipping country must match specified country! if($shipping['country'] !== $this->country) { throw new KlarnaException('Error in ' . __METHOD__ . ': Shipping address country must match the country set!', 50036); } $tmp = array( $pno, $gender, $this->reference, $this->reference_code, $this->orderid[0], $this->orderid[1], $shipping, $billing, $this->getClientIP(), $flags, $this->currency, $this->country, $this->language, $this->eid, $digestSecret, $encoding, $pclass, $this->goodsList, $this->comment, $this->shipInfo, $this->travelInfo, $this->incomeInfo, $this->bankInfo, $this->sid, $this->extraInfo ); self::printDebug('add_invoice', $tmp); $result = $this->xmlrpc_call('add_invoice', $tmp); if($clear === true) { //Make sure any stored values that need to be unique between purchases are cleared. foreach($this->coObjects as $co) { $co->clear(); } $this->clear(); } self::printDebug('add_invoice result', $result); return $result; } /** * Activates previously created invoice (from {@link Klarna::addTransaction()}). * * <b>Note</b>:<br> * If you want to change the shipment type, you can specify it using:<br> * {@link Klarna::setShipmentInfo() Klarna::setShipmentInfo('delay_adjust', ...)}<br> * with either: {@link KlarnaFlags::NORMAL_SHIPMENT NORMAL_SHIPMENT} or {@link KlarnaFlags::EXPRESS_SHIPMENT EXPRESS_SHIPMENT}<br> * * * @see Klarna::setShipmentInfo() * @link http://integration.klarna.com/en/api/standard-integration/functions/activateinvoice * @param string $invNo Invoice number. * @param int $pclass PClass id used for this invoice. * @param bool $clear Whether customer info should be cleared after this call. * @throws KlarnaException * @return string An URL to the PDF invoice. */ public function activateInvoice($invNo, $pclass = KlarnaPClass::INVOICE, $clear = true) { $this->checkInvNo($invNo, __METHOD__); $digestSecret = self::digest($this->colon($this->eid, $invNo, $this->secret)); $paramList = array($this->eid, $invNo, $digestSecret, $pclass, $this->shipInfo); self::printDebug('activate_invoice', $paramList); $result = $this->xmlrpc_call('activate_invoice', $paramList); if($clear === true) { $this->clear(); } self::printDebug('activate_invoice result', $result); return $result; } /** * Removes a passive invoices which has previously been created with {@link Klarna::addTransaction()}.<br> * True is returned if the invoice was successfully removed, otherwise an exception is thrown.<br> * * @param string $invno Invoice number. * @throws KlarnaException * @return bool */ public function deleteInvoice($invNo) { $this->checkInvNo($invNo, __METHOD__); $digestSecret = self::digest($this->colon($this->eid, $invNo, $this->secret)); $paramList = array($this->eid, $invNo, $digestSecret); self::printDebug('delete_invoice', $paramList); $result = $this->xmlrpc_call('delete_invoice', $paramList); return ($result == 'ok') ? true : false; } /** * Reserves a purchase amount for a specific customer. <br> * The reservation is valid, by default, for 7 days.<br> * * <b>This method returns an array with</b>:<br> * A reservation number (rno)<br> * Order status flag<br> * * <b>Order status can be</b>:<br> * {@link KlarnaFlags::ACCEPTED}<br> * {@link KlarnaFlags::PENDING}<br> * {@link KlarnaFlags::DENIED}<br> * * <b>Please note</b>:<br> * Activation must be done with activate_reservation, i.e. you cannot activate through Klarna Online.<br> * * Gender is only required for Germany and Netherlands.<br> * * <b>Flags can be set to</b>:<br> * {@link KlarnaFlags::NO_FLAG}<br> * {@link KlarnaFlags::TEST_MODE}<br> * {@link KlarnaFlags::RSRV_SENSITIVE_ORDER}<br> * {@link KlarnaFlags::RSRV_PHONE_TRANSACTION}<br> * {@link KlarnaFlags::RSRV_SEND_PHONE_PIN}<br> * * Some flags can be added to each other for multiple options. * * <b>Note</b>:<br> * Normal shipment type is assumed unless otherwise specified, you can do this by calling:<br> * {@link Klarna::setShipmentInfo() Klarna::setShipmentInfo('delay_adjust', ...)}<br> * with either: {@link KlarnaFlags::NORMAL_SHIPMENT NORMAL_SHIPMENT} or {@link KlarnaFlags::EXPRESS_SHIPMENT EXPRESS_SHIPMENT}<br> * * @link http://integration.klarna.com/en/api/advanced-integration/functions/reserveamount * @param string $pno Personal number, SSN, date of birth, etc. * @param int $gender {@link KlarnaFlags::FEMALE} or {@link KlarnaFlags::MALE}, null for unspecified. * @param int $amount Amount to be reserved, including VAT. * @param int $flags Options which affect the behaviour. * @param int $pclass {@link KlarnaPClass::getId() PClass ID}. * @param int $encoding {@link KlarnaEncoding PNO Encoding} constant. * @param bool $clear Whether customer info should be cleared after this call. * @throws KlarnaException * @return array An array with reservation number and order status. [string, int] */ public function reserveAmount($pno, $gender, $amount, $flags = 0, $pclass = KlarnaPClass::INVOICE, $encoding = null, $clear = true) { if(!is_int($this->country) || !is_int($this->language) || !is_int($this->currency)) { throw new KlarnaException('Error in ' . __METHOD__ . ': You must set country, language and currency!', 50023); } $encoding = ($encoding === null) ? $this->getPNOEncoding() : $encoding; $this->checkPNO($pno, $encoding, __METHOD__); if($gender === 'm') { $gender = KlarnaFlags::MALE; } else if($gender === 'f') { $gender = KlarnaFlags::FEMALE; } if($gender !== null) { $this->checkInt($gender, 'gender', __METHOD__); } $this->checkInt($flags, 'flags', __METHOD__); $this->checkInt($pclass, 'pclass', __METHOD__); if(!is_array($this->goodsList) || empty($this->goodsList)) { throw new KlarnaException("Error in " . __METHOD__ . ": No articles in goods list!", 50038); } //Calculate automatically the amount from goodsList. if($amount === -1) { $amount = 0; foreach($this->goodsList as $goods) { $amount += floatval($goods['goods']['price']) * intval($goods['qty']); } if(is_numeric($amount) && !is_int($amount)) { $amount = intval($amount); } if(!is_numeric($amount) || !is_int($amount)) { throw new KlarnaException("Error in " . __METHOD__ . ": Price not an integer! ($amount)", 50039); } } else { $this->checkAmount($amount, __METHOD__); } if($amount <= 0) { throw new KlarnaException("Error in " . __METHOD__ . ": Amount needs to be larger than 0! ($amount)", 50040); } //No addresses used for phone transactions $billing = $shipping = ''; if( !($flags & KlarnaFlags::RSRV_PHONE_TRANSACTION) ) { $billing = $this->assembleAddr(__METHOD__, $this->billing); $shipping = $this->assembleAddr(__METHOD__, $this->shipping); if($shipping['country'] !== $this->country) { throw new KlarnaException('Error in ' . __METHOD__ . ': Shipping address country must match the country set!', 50041); } } //Assume normal shipment unless otherwise specified. if(!isset($this->shipInfo['delay_adjust'])) { $this->setShipmentInfo('delay_adjust', KlarnaFlags::NORMAL_SHIPMENT); } //Make sure we get any session ID's or similar $this->initCheckout($this, $this->eid); $digestSecret = self::digest($this->colon($this->eid, $pno, $amount, $this->secret)); $paramList = array( $pno, $gender, $amount, $this->reference, $this->reference_code, $this->orderid[0], $this->orderid[1], $shipping, $billing, $this->getClientIP(), $flags, $this->currency, $this->country, $this->language, $this->eid, $digestSecret, $encoding, $pclass, $this->goodsList, $this->comment, $this->shipInfo, $this->travelInfo, $this->incomeInfo, $this->bankInfo, $this->sid, $this->extraInfo ); self::printDebug('reserve_amount', $paramList); $result = $this->xmlrpc_call('reserve_amount', $paramList); if($clear === true) { //Make sure any stored values that need to be unique between purchases are cleared. foreach($this->coObjects as $co) { $co->clear(); } $this->clear(); } self::printDebug('reserve_amount result', $result); return $result; } /** * Cancels a reservation. * * @link http://integration.klarna.com/en/api/advanced-integration/functions/cancelreservation * @param string $rno Reservation number. * @throws KlarnaException * @return bool True, if the cancellation was successful. */ public function cancelReservation($rno) { $this->checkRNO($rno, __METHOD__); $digestSecret = self::digest($this->colon($this->eid, $rno, $this->secret)); $paramList = array($rno, $this->eid, $digestSecret); self::printDebug('cancel_reservation', $paramList); $result = $this->xmlrpc_call('cancel_reservation', $paramList); return ($result == 'ok') ? true : false; } /** * Changes specified reservation to a new amount. * * <b>Flags can be either of these</b>:<br> * {@link KlarnaFlags::NEW_AMOUNT}<br> * {@link KlarnaFlags::ADD_AMOUNT}<br> * * @link http://integration.klarna.com/en/api/advanced-integration/functions/changereservation * @param string $rno Reservation number. * @param int $amount Amount including VAT. * @param int $flags Options which affect the behaviour. * @throws KlarnaException * @return bool True, if the change was successful. */ public function changeReservation($rno, $amount, $flags = KlarnaFlags::NEW_AMOUNT) { $this->checkRNO($rno, __METHOD__); $this->checkAmount($amount, __METHOD__); $this->checkInt($flags, 'flags', __METHOD__); $digestSecret = self::digest($this->colon($this->eid, $rno, $amount, $this->secret)); $paramList = array($rno, $amount, $this->eid, $digestSecret, $flags); self::printDebug('change_reservation', $paramList); $result = $this->xmlrpc_call('change_reservation', $paramList); return ($result == 'ok') ? true : false; } /** * Activates a previously created reservation. * * <b>This method returns an array with</b>:<br> * Risk status ("no_risk", "ok")<br> * Invoice number<br> * * Gender is only required for Germany and Netherlands.<br> * * Use of the OCR parameter is optional, a OCR number can be retrieved by using:<br> * {@link Klarna::reserveOCR()} or {@link Klarna::reserveOCRemail()}.<br> * * <b>Flags can be set to</b>:<br> * {@link KlarnaFlags::NO_FLAG}<br> * {@link KlarnaFlags::TEST_MODE}<br> * {@link KlarnaFlags::RSRV_SEND_BY_MAIL}<br> * {@link KlarnaFlags::RSRV_SEND_BY_EMAIL}<br> * {@link KlarnaFlags::RSRV_PRESERVE_RESERVATION}<br> * {@link KlarnaFlags::RSRV_SENSITIVE_ORDER}<br> * * Some flags can be added to each other for multiple options. * * <b>Note</b>:<br> * Normal shipment type is assumed unless otherwise specified, you can do this by calling:<br> * {@link Klarna::setShipmentInfo() Klarna::setShipmentInfo('delay_adjust', ...)}<br> * with either: {@link KlarnaFlags::NORMAL_SHIPMENT NORMAL_SHIPMENT} or {@link KlarnaFlags::EXPRESS_SHIPMENT EXPRESS_SHIPMENT}<br> * * @see Klarna::reserveAmount() * * @link http://integration.klarna.com/en/api/advanced-integration/functions/activatereservation * @param string $pno Personal number, SSN, date of birth, etc. * @param string $rno Reservation number. * @param int $gender {@link KlarnaFlags::FEMALE} or {@link KlarnaFlags::MALE}, null for unspecified. * @param string $ocr A OCR number. * @param int $flags Options which affect the behaviour. * @param int $pclass {@link KlarnaPClass::getId() PClass ID}. * @param int $encoding {@link KlarnaEncoding PNO Encoding} constant. * @param bool $clear Whether customer info should be cleared after this call. * @throws KlarnaException * @return array An array with risk status and invoice number [string, string]. */ public function activateReservation($pno, $rno, $gender, $ocr = "", $flags = KlarnaFlags::NO_FLAG, $pclass = KlarnaPClass::INVOICE, $encoding = null, $clear = true) { if(!is_int($this->country) || !is_int($this->language) || !is_int($this->currency)) { throw new KlarnaException('Error in ' . __METHOD__ . ': You must set country, language and currency!', 50023); } $encoding = ($encoding === null) ? $this->getPNOEncoding() : $encoding; $this->checkPNO($pno, $encoding, __METHOD__); $this->checkRNO($rno, __METHOD__); if($gender !== null) { $this->checkInt($gender, 'gender', __METHOD__); } $this->checkOCR($ocr, __METHOD__); $this->checkRef($this->reference, $this->reference_code, __METHOD__); if(!is_array($this->goodsList) || empty($this->goodsList)) { throw new KlarnaException("Error in " . __METHOD__ . ": No articles in goods list!", 50043); } //No addresses used for phone transactions $billing = $shipping = ''; if( !($flags & KlarnaFlags::RSRV_PHONE_TRANSACTION) ) { $billing = $this->assembleAddr(__METHOD__, $this->billing); $shipping = $this->assembleAddr(__METHOD__, $this->shipping); if($shipping['country'] !== $this->country) { throw new KlarnaException('Error in ' . __METHOD__ . ': Shipping address country must match the country set!', 50044); } } //activate digest $string = $this->eid . ":" . $pno . ":"; if(is_array($this->goodsList)) { foreach($this->goodsList as $goods) { $string .= $goods["goods"]["artno"] . ":" . $goods["qty"] . ":"; } } $digestSecret = self::digest($string . $this->secret); //end digest //Assume normal shipment unless otherwise specified. if(!isset($this->shipInfo['delay_adjust'])) { $this->setShipmentInfo('delay_adjust', KlarnaFlags::NORMAL_SHIPMENT); } $paramList = array( $rno, $ocr, $pno, $gender, $this->reference, $this->reference_code, $this->orderid[0], $this->orderid[1], $shipping, $billing, $this->getClientIP(), $flags, $this->currency, $this->country, $this->language, $this->eid, $digestSecret, $encoding, $pclass, $this->goodsList, $this->comment, $this->shipInfo, $this->travelInfo, $this->incomeInfo, $this->bankInfo, $this->extraInfo ); self::printDebug('activate_reservation', $paramList); $result = $this->xmlrpc_call('activate_reservation', $paramList); if($clear === true) { $this->clear(); } self::printDebug('activate_reservation result', $result); return $result; } /** * Splits a reservation due to for example outstanding articles. * * <b>For flags usage see</b>:<br> * {@link Klarna::reserveAmount()}<br> * * @link http://integration.klarna.com/en/api/advanced-integration/functions/splitreservation * @param string $rno Reservation number. * @param int $amount The amount to be subtracted from the reservation. * @param int $flags Options which affect the behaviour. * @throws KlarnaException * @return string A new reservation number. */ public function splitReservation($rno, $amount, $flags = KlarnaFlags::NO_FLAG) { //Check so required information is set. $this->checkRNO($rno, __METHOD__); $this->checkAmount($amount, __METHOD__); if($amount <= 0) { throw new KlarnaException("Error in " . __METHOD__ . ": Amount needs to be above 0!", 50045); } $digestSecret = self::digest($this->colon($this->eid, $rno, $amount, $this->secret)); $paramList = array($rno, $amount, $this->orderid[0], $this->orderid[1], $flags, $this->eid, $digestSecret); self::printDebug('split_reservation array', $paramList); $result = $this->xmlrpc_call('split_reservation', $paramList); self::printDebug('split_reservation result', $result); return $result; } /** * Reserves a specified number of OCR numbers.<br> * For the specified country or the {@link Klarna::setCountry() set country}.<br> * * @link http://integration.klarna.com/en/api/advanced-integration/functions/reserveocrnums * @param int $no The number of OCR numbers to reserve. * @param int $country {@link KlarnaCountry} constant. * @throws KlarnaException * @return array An array of OCR numbers. */ public function reserveOCR($no, $country = null) { $this->checkNo($no, __METHOD__); if($country === null) { if(!$this->country) { throw new KlarnaException('Error in' . __METHOD__ . ': You must set country first!', 50046); } $country = $this->country; } else { $this->checkCountry($country, __METHOD__); } $digestSecret = self::digest($this->colon($this->eid, $no, $this->secret)); $paramList = array($no, $this->eid, $digestSecret, $country); self::printDebug('reserve_ocr_nums array', $paramList); return $this->xmlrpc_call('reserve_ocr_nums', $paramList); } /** * Reserves the number of OCRs specified and sends them to the given email. * * @param int $no Number of OCR numbers to reserve. * @param string $email Email address. * @param int $country {@link KlarnaCountry} constant. * @return bool True, if the OCRs were reserved and sent. */ public function reserveOCRemail($no, $email, $country = null) { $this->checkNo($no, __METHOD__); $this->checkPNO($email, KlarnaEncoding::EMAIL, __METHOD__); if($country === null) { if(!$this->country) { throw new KlarnaException('Error in' . __METHOD__ . ': You must set country first!', 50046); } $country = $this->country; } else { $this->checkCountry($country, __METHOD__); } $digestSecret = self::digest($this->colon($this->eid, $no, $this->secret)); $paramList = array($no, $email, $this->eid, $digestSecret, $country); self::printDebug('reserve_ocr_nums_email array', $paramList); $result = $this->xmlrpc_call('reserve_ocr_nums_email', $paramList); return ($result == 'ok'); } /** * Checks if the specified SSN/PNO has an part payment account with Klarna. * * @link http://integration.klarna.com/en/api/standard-integration/functions/hasaccount * @param string $pno Social security number, Personal number, ... * @param int $encoding {@link KlarnaEncoding PNO Encoding} constant. * @throws KlarnaException * @return bool True, if customer has an account. */ public function hasAccount($pno, $encoding = null) { $encoding = ($encoding === null) ? $this->getPNOEncoding() : $encoding; $this->checkPNO($pno, $encoding, __METHOD__); $digest = self::digest($this->colon($this->eid, $pno, $this->secret)); $paramList = array($this->eid, $pno, $digest, $encoding); self::printDebug('has_account', $paramList); $result = $this->xmlrpc_call('has_account', $paramList); return ($result === 'true') ? true : false; } /** * Adds an article number and quantity to be used in {@link Klarna::activatePart()}, {@link Klarna::creditPart()} and {@link Klarna::invoicePartAmount()}. * * @link http://integration.klarna.com/en/api/invoice-handling-functions/functions/mkartno * @param int $qty Quantity of specified article. * @param string $artNo Article number. * @throws KlarnaException * @return void */ public function addArtNo($qty, $artNo) { $this->checkQty($qty, __METHOD__); $this->checkArtNo($artNo, __METHOD__); if(!is_array($this->artNos)) { $this->artNos = array(); } $this->artNos[] = array('artno' => $artNo, 'qty' => $qty); } /** * Partially activates a passive invoice. * * Returned array contains index "url" and "invno".<br> * The value of "url" is a URL pointing to a temporary PDF-version of the activated invoice.<br> * The value of "invno" is either 0 if the entire invoice was activated or the number on the new passive invoice.<br> * * <b>Note</b>:<br> * You need to call {@link Klarna::addArtNo()} first, to specify which articles and how many you want to partially activate.<br><br> * If you want to change the shipment type, you can specify it using:<br> * {@link Klarna::setShipmentInfo() Klarna::setShipmentInfo('delay_adjust', ...)}<br> * with either: {@link KlarnaFlags::NORMAL_SHIPMENT NORMAL_SHIPMENT} or {@link KlarnaFlags::EXPRESS_SHIPMENT EXPRESS_SHIPMENT}<br> * * @see Klarna::addArtNo() * @see Klarna::activateInvoice() * * @link http://integration.klarna.com/en/api/standard-integration/functions/activatepart * @param string $invNo Invoice numbers. * @param int $pclass PClass id used for this invoice. * @param bool $clear Whether customer info should be cleared after this call. * @throws KlarnaException * @return array An array with invoice URL and invoice number. ['url' => val, 'invno' => val] */ public function activatePart($invNo, $pclass = KlarnaPClass::INVOICE, $clear = true) { $this->checkInvNo($invNo, __METHOD__); $this->checkArtNos($this->artNos, __METHOD__); self::printDebug('activate_part artNos array', $this->artNos); //function activate_part_digest $string = $this->eid . ":" . $invNo . ":"; foreach($this->artNos as $artNo) { $string .= $artNo["artno"] . ":". $artNo["qty"] . ":"; } $digestSecret = self::digest($string . $this->secret); //end activate_part_digest $paramList = array($this->eid, $invNo, $this->artNos, $digestSecret, $pclass, $this->shipInfo); self::printDebug('activate_part array', $paramList); $result = $this->xmlrpc_call('activate_part', $paramList); if($clear === true) { $this->clear(); } self::printDebug('activate_part result', $result); return $result; } /** * Retrieves the total amount for an active invoice. * * @link http://integration.klarna.com/en/api/other-functions/functions/invoiceamount * @param string $invNo Invoice number. * @throws KlarnaException * @return float The total amount. */ public function invoiceAmount($invNo) { $this->checkInvNo($invNo, __METHOD__); $digestSecret = self::digest($this->colon($this->eid, $invNo, $this->secret)); $paramList = array($this->eid, $invNo, $digestSecret); self::printDebug('invoice_amount array', $paramList); $result = $this->xmlrpc_call('invoice_amount', $paramList); //Result is in cents, fix it. return ($result / 100); } /** * Changes the order number of a purchase that was set when the order was made online. * * @link http://integration.klarna.com/en/api/other-functions/functions/updateorderno * @param string $invNo Invoice number. * @param string $orderid Estores order number. * @throws KlarnaException * @return string Invoice number. */ public function updateOrderNo($invNo, $orderid) { $this->checkInvNo($invNo, __METHOD__); $this->checkEstoreOrderNo($orderid, __METHOD__); $digestSecret = self::digest($this->colon($invNo, $orderid, $this->secret)); $paramList = array($this->eid, $digestSecret, $invNo, $orderid); self::printDebug('update_orderno array', $paramList); $result = $this->xmlrpc_call('update_orderno', $paramList); return $result; } /** * Sends an activated invoice to the customer via e-mail. <br> * The email is sent in plain text format and contains a link to a PDF-invoice.<br> * * <b>Please note!</b><br> * Regular postal service is used if the customer has not entered his/her e-mail address when making the purchase (charges may apply).<br> * * @link http://integration.klarna.com/en/api/invoice-handling-functions/functions/emailinvoice * @param string $invNo Invoice number. * @throws KlarnaException * @return string Invoice number. */ public function emailInvoice($invNo) { $this->checkInvNo($invNo, __METHOD__); $digestSecret = self::digest($this->colon($this->eid, $invNo, $this->secret)); $paramList = array($this->eid, $invNo, $digestSecret); self::printDebug('email_invoice array', $paramList); $result = $this->xmlrpc_call('email_invoice', $paramList); return $result; } /** * Requests a postal send-out of an activated invoice to a customer by Klarna (charges may apply). * * @link http://integration.klarna.com/en/api/invoice-handling-functions/functions/sendinvoice * @param string $invNo Invoice number. * @throws KlarnaException * @return string Invoice number. */ public function sendInvoice($invNo) { $this->checkInvNo($invNo, __METHOD__); $digestSecret = self::digest($this->colon($this->eid, $invNo, $this->secret)); $paramList = array($this->eid, $invNo, $digestSecret); self::printDebug('send_invoice array', $paramList); $result = $this->xmlrpc_call('send_invoice', $paramList); return $result; } /** * Gives discounts on invoices.<br> * If you are using standard integration and the purchase is not yet activated (you have not yet delivered the goods), <br> * just change the article list in our online interface Klarna Online.<br> * * <b>Flags can be</b>:<br> * {@link KlarnaFlags::INC_VAT}<br> * {@link KlarnaFlags::NO_FLAG}, <b>NOT RECOMMENDED!</b><br> * * @link http://integration.klarna.com/en/api/invoice-handling-functions/functions/returnamount * @param string $invNo Invoice number. * @param int $amount The amount given as a discount. * @param float $vat VAT in percent, e.g. 22.2 for 22.2%. * @param int $flags If amount is {@link KlarnaFlags::INC_VAT including} or {@link KlarnaFlags::NO_FLAG excluding} VAT. * @throws KlarnaException * @return string Invoice number. */ public function returnAmount($invNo, $amount, $vat, $flags = KlarnaFlags::INC_VAT) { $this->checkInvNo($invNo, __METHOD__); $this->checkAmount($amount, __METHOD__); $this->checkVAT($vat, __METHOD__); $this->checkInt($flags, 'flags', __METHOD__); $digestSecret = self::digest($this->colon($this->eid, $invNo, $this->secret)); $paramList = array($this->eid, $invNo, $amount, $vat, $digestSecret, $flags); self::printDebug('return_amount', $paramList); $result = $this->xmlrpc_call('return_amount', $paramList); return $result; } /** * Performs a complete refund on an invoice, part payment and mobile purchase. * * @link http://integration.klarna.com/en/api/invoice-handling-functions/functions/creditinvoice * @param string $invNo Invoice number. * @param string $credNo Credit number. * @throws KlarnaException * @return string Invoice number. */ public function creditInvoice($invNo, $credNo = "") { $this->checkInvNo($invNo, __METHOD__); $this->checkCredNo($credNo, __METHOD__); $digestSecret = self::digest($this->colon($this->eid, $invNo, $this->secret)); $paramList = array($this->eid, $invNo, $credNo, $digestSecret); self::printDebug('credit_invoice', $paramList); $result = $this->xmlrpc_call('credit_invoice', $paramList); return $result; } /** * Performs a partial refund on an invoice, part payment or mobile purchase.<br> * * <b>Note</b>:<br> * You need to call {@link Klarna::addArtNo()} first.<br> * * @see Klarna::addArtNo() * * @link http://integration.klarna.com/en/api/invoice-handling-functions/functions/creditpart * @param string $invNo Invoice number. * @param string $credNo Credit number. * @throws KlarnaException * @return string Invoice number. */ public function creditPart($invNo, $credNo = "") { $this->checkInvNo($invNo, __METHOD__); $this->checkCredNo($credNo, __METHOD__); $this->checkArtNos($this->artNos, __METHOD__); //function activate_part_digest $string = $this->eid . ":" . $invNo . ":"; foreach($this->artNos as $artNo) { $string .= $artNo["artno"] . ":". $artNo["qty"] . ":"; } $digestSecret = self::digest($string . $this->secret); //end activate_part_digest $paramList = array($this->eid, $invNo, $this->artNos, $credNo, $digestSecret); $this->artNos = array(); self::printDebug('credit_part', $paramList); $result = $this->xmlrpc_call('credit_part', $paramList); return $result; } /** * Changes the quantity of a specific item in a passive invoice. * * @link http://integration.klarna.com/en/api/other-functions/functions/updategoodsqty * @param string $invNo Invoice number. * @param string $artNo Article number. * @param int $qty Quantity of specified article. * @throws KlarnaException * @return string Invoice number. */ public function updateGoodsQty($invNo, $artNo, $qty) { $this->checkInvNo($invNo, __METHOD__); $this->checkQty($qty, __METHOD__); $this->checkArtNo($artNo, __METHOD__); $digestSecret = self::digest($this->colon($invNo, $artNo, $qty, $this->secret)); $paramList = array($this->eid, $digestSecret, $invNo, $artNo, $qty); self::printDebug('update_goods_qty', $paramList); $result = $this->xmlrpc_call('update_goods_qty', $paramList); return $result; } /** * Changes the amount of a fee (e.g. the invoice fee) in a passive invoice. * * <b>Type can be</b>:<br> * {@link KlarnaFlags::IS_SHIPMENT}<br> * {@link KlarnaFlags::IS_HANDLING}<br> * * * @link http://integration.klarna.com/en/api/other-functions/functions/updatechargeamount * @param string $invNo Invoice number. * @param int $type Charge type. * @param int $newAmount The new amount for the charge. * @throws KlarnaException * @return string Invoice number. */ public function updateChargeAmount($invNo, $type, $newAmount) { $this->checkInvNo($invNo, __METHOD__); $this->checkInt($type, 'type', __METHOD__); $this->checkAmount($newAmount, __METHOD__); if($type === KlarnaFlags::IS_SHIPMENT) { $type = 1; } else if($type === KlarnaFlags::IS_HANDLING) { $type = 2; } $digestSecret = self::digest($this->colon($invNo, $type, $newAmount, $this->secret)); $paramList = array($this->eid, $digestSecret, $invNo, $type, $newAmount); self::printDebug('update_charge_amount', $paramList); $result = $this->xmlrpc_call('update_charge_amount', $paramList); return $result; } /** * The invoice_address function is used to retrieve the address of a purchase. * * * * @link http://integration.klarna.com/en/api/other-functions/functions/invoiceaddress * @param string $invNo Invoice number. * @throws KlarnaException * @return KlarnaAddr */ public function invoiceAddress($invNo) { $this->checkInvNo($invNo, __METHOD__); $digestSecret = self::digest($this->colon($this->eid, $invNo, $this->secret)); $paramList = array($this->eid, $invNo, $digestSecret); self::printDebug('invoice_address', $paramList); $result = $this->xmlrpc_call('invoice_address', $paramList); $addr = new KlarnaAddr(); if(strlen($result[0]) > 0) { $addr->isCompany = false; $addr->setFirstName($result[0]); $addr->setLastName($result[1]); } else { $addr->isCompany = true; $addr->setCompanyName($result[1]); } $addr->setStreet($result[2]); $addr->setZipCode($result[3]); $addr->setCity($result[4]); $addr->setCountry($result[5]); return $addr; } /** * Retrieves the amount of a specific goods from a purchase. * * <b>Note</b>:<br> * You need to call {@link Klarna::addArtNo()} first.<br> * * @see Klarna::addArtNo() * * @link http://integration.klarna.com/en/api/other-functions/functions/invoicepartamount * @param string $invNo Invoice number. * @throws KlarnaException * @return float The amount of the goods. */ public function invoicePartAmount($invNo) { $this->checkInvNo($invNo, __METHOD__); $this->checkArtNos($this->artNos, __METHOD__); //function activate_part_digest $string = $this->eid . ":" . $invNo . ":"; foreach($this->artNos as $artNo) { $string .= $artNo["artno"] . ":". $artNo["qty"] . ":"; } $digestSecret = self::digest($string . $this->secret); //end activate_part_digest $paramList = array($this->eid, $invNo, $this->artNos, $digestSecret); $this->artNos = array(); self::printDebug('invoice_part_amount', $paramList); $result = $this->xmlrpc_call('invoice_part_amount', $paramList); return ($result / 100); } /** * Returns the current order status for a specific reservation or invoice.<br> * Use this when {@link Klarna::addTransaction()} or {@link Klarna::reserveAmount()} returns a {@link KlarnaFlags::PENDING} status.<br> * * <b>Order status can be</b>:<br> * {@link KlarnaFlags::ACCEPTED}<br> * {@link KlarnaFlags::PENDING}<br> * {@link KlarnaFlags::DENIED}<br> * * @link http://integration.klarna.com/en/api/other-functions/functions/checkorderstatus * @param string $id Reservation number or invoice number. * @param int $type 0, if $id is an invoice or reservation, 1 for order id. * @throws KlarnaException * @return string The order status. */ public function checkOrderStatus($id, $type = 0) { if(!is_string($id)) { $id = strval($id); } if(strlen($id) == 0) { throw new KlarnaException("Error in " . __METHOD__ . ": No ID set!", 50048); } $this->checkInt($type, 'type', __METHOD__); if($type !== 0 && $type !== 1) { throw new KlarnaException('Error in ' . __METHOD__ . ': Unknown type! ('.$type.')', 50049); } $digestSecret = self::digest($this->colon($this->eid, $id, $this->secret)); $paramList = array($this->eid, $digestSecret, $id, $type); self::printDebug('check_order_status', $paramList); $result = $this->xmlrpc_call('check_order_status', $paramList); return $result; } /** * Retrieves a list of all the customer numbers associated with the specified pno. * * @param string $pno Social security number, Personal number, ... * @param int $encoding {@link KlarnaEncoding PNO Encoding} constant. * @throws KlarnaException * @return array An array containing all customer numbers associated with that pno. */ public function getCustomerNo($pno, $encoding = null) { $encoding = ($encoding === null) ? $this->getPNOEncoding() : $encoding; $this->checkPNO($pno, $encoding, __METHOD__); $digestSecret = self::digest($this->colon($this->eid, $pno, $this->secret)); $paramList = array($pno, $this->eid, $digestSecret, $encoding); self::printDebug('get_customer_no', $paramList); $result = $this->xmlrpc_call('get_customer_no', $paramList); return $result; } /** * Associates a pno with a customer number when you want to make future purchases without a pno. * * @param string $pno Social security number, Personal number, ... * @param string $custNo The customer number. * @param int $encoding {@link KlarnaEncoding PNO Encoding} constant. * @throws KlarnaException * @return bool True, if the customer number was associated with the pno. */ public function setCustomerNo($pno, $custNo, $encoding = null) { $encoding = ($encoding === null) ? $this->getPNOEncoding() : $encoding; $this->checkPNO($pno, $encoding, __METHOD__); if(!is_string($custNo)) { $custNo = strval($custNo); } if(strlen($custNo) == 0) { throw new KlarnaException("Error in " . __METHOD__ . ": No customer number set!", 50050); } $digestSecret = self::digest($this->colon($this->eid, $pno, $custNo, $this->secret)); $paramList = array($pno, $custNo, $this->eid, $digestSecret, $encoding); self::printDebug('set_customer_no', $paramList); $result = $this->xmlrpc_call('set_customer_no', $paramList); return ($result == 'ok'); } /** * Removes a customer number from association with a pno. * * @param string $custNo The customer number. * @throws KlarnaException * @return bool True, if the customer number association was removed. */ public function removeCustomerNo($custNo) { if(!is_string($custNo)) { $custNo = strval($custNo); } if(strlen($custNo) == 0) { throw new KlarnaException("Error in " . __METHOD__ . ": No customer number set!", 50051); } $digestSecret = self::digest($this->colon($this->eid, $custNo, $this->secret)); $paramList = array($custNo, $this->eid, $digestSecret); self::printDebug('remove_customer_no', $paramList); $result = $this->xmlrpc_call('remove_customer_no', $paramList); return ($result == 'ok'); } /** * Updates email on all invoices (and reservations?) for specified pno and store/eid. * * @param string $pno Social security number, Personal number, ... * @param string $email Email address. * @return bool True, if the email was successfully updated for specified pno. */ public function updateEmail($pno, $email) { //check $pno how? which encoding? $this->checkPNO($email, KlarnaEncoding::EMAIL, __METHOD__); $digestSecret = self::digest($this->colon($pno, $email, $this->secret)); $paramList = array($this->eid, $digestSecret, $pno, $email); self::printDebug('update_email', $paramList); $result = $this->xmlrpc_call('update_email', $paramList); return ($result == 'ok'); } /** * Sets notes/log information for the specified invoice number. * * @param string $invNo Invoice number. * @param string $notes Note(s) to be associated with the invoice. * @throws KlarnaException * @return string Invoice number. */ public function updateNotes($invNo, $notes) { $this->checkInvNo($invNo, __METHOD__); if(!is_string($notes)) { $notes = strval($notes); } $digestSecret = self::digest($this->colon($invNo, $notes, $this->secret)); $paramList = array($this->eid, $digestSecret, $invNo, $notes); self::printDebug('update_notes', $paramList); return $this->xmlrpc_call('update_notes', $paramList); } /** * Returns the specified PCStorage object. * * @ignore Do not show this in PHPDoc. * @throws Exception|KlarnaException * @return PCStorage */ protected function getPCStorage() { //require_once('pclasses/storage.intf.php'); $className = $this->pcStorage.'storage'; $pclassStorage = JPATH_VMKLARNAPLUGIN . DS . 'klarna' . DS . 'api' . DS . 'pclasses' . DS . $className.'.class.php'; require_once($pclassStorage); $storage = new $className; if(!($storage instanceof PCStorage)) { throw new Exception($className . ' located in ' . $pclassStorage . ' is not a PCStorage instance.', 50052); } return $storage; } /** * Fetches the PClasses from backend.<br> * Removes the cached/stored pclasses and updates.<br> * You are only allowed to call this once, or once per update of PClasses in KO.<br> * * <b>Note</b>:<br> * If all parameters are omitted or null, all PClasses (for all countries) will be fetched.<br> * If language and/or currency is null, then they will be set to mirror the specified country.<br/> * Short codes like DE, SV or EUR can also be used instead of the constants.<br/> * * @param string|int $country {@link KlarnaCountry Country} constant, or two letter code. * @param mixed $language {@link KlarnaLanguage Language} constant, or two letter code. * @param mixed $currency {@link KlarnaCurrency Currency} constant, or three letter code. * @throws KlarnaException * @return void */ public function fetchPClasses($country = null, $language = null, $currency = null) { $countries = array(); if($country === null && $language === null && $currency === null) { $countries = array( array( 'country' => KlarnaCountry::DE, 'language' => KlarnaLanguage::DE, 'currency' => KlarnaCurrency::EUR ),array( 'country' => KlarnaCountry::DK, 'language' => KlarnaLanguage::DA, 'currency' => KlarnaCurrency::DKK ),array( 'country' => KlarnaCountry::FI, 'language' => KlarnaLanguage::FI, 'currency' => KlarnaCurrency::EUR ),array( 'country' => KlarnaCountry::NL, 'language' => KlarnaLanguage::NL, 'currency' => KlarnaCurrency::EUR ),array( 'country' => KlarnaCountry::NO, 'language' => KlarnaLanguage::NB, 'currency' => KlarnaCurrency::NOK ),array( 'country' => KlarnaCountry::SE, 'language' => KlarnaLanguage::SV, 'currency' => KlarnaCurrency::SEK ), ); } else { if(!is_numeric($country) && (strlen($country) == 2 || strlen($country) == 3)) { $country = self::getCountryForCode($country); } $this->checkCountry($country, __METHOD__); if($currency === null) { $currency = $this->getCurrencyForCountry($country); } else if(!is_numeric($currency) && strlen($currency) == 3) { $currency = self::getCurrencyForCode($currency); } $this->checkCurrency($currency, __METHOD__); if($language === null) { $language = $this->getLanguageForCountry($country); } else if(!is_numeric($language) && strlen($language) == 2) { $language = self::getLanguageForCode($language); } $this->checkLanguage($language, __METHOD__); $countries = array( array( 'country' => $country, 'language' => $language, 'currency' => $currency ) ); } try { if($this->config instanceof ArrayAccess) { $pclasses = $this->getPCStorage(); try { //Attempt to load previously stored, so they aren't accidentially removed. $pclasses->load($this->pcURI); } catch(Exception $e) { //Silently fail } catch(KlarnaException $e) { //Silently fail } foreach($countries as $item) { $digestSecret = self::digest($this->colon($this->eid, $item['currency'], $this->secret)); $paramList = array($this->eid, $item['currency'], $digestSecret, $item['country'], $item['language']); self::printDebug('get_pclasses array', $paramList); $result = $this->xmlrpc_call('get_pclasses', $paramList); self::printDebug('get_pclasses result', $result); foreach($result as &$pclass) { //numeric htmlentities $pclass[1] = Klarna::num_htmlentities($pclass[1]); //Below values are in "cents", fix them. $pclass[3] /= 100; //divide start fee with 100 $pclass[4] /= 100; //divide invoice fee with 100 $pclass[5] /= 100; //divide interest rate with 100 $pclass[6] /= 100; //divide min amount with 100 if($pclass[9] != '-') { $pclass[9] = strtotime($pclass[9]); //unix timestamp instead of yyyy-mm-dd } array_unshift($pclass, $this->eid); //Associate the PClass with this estore. $pclasses->addPClass(new KlarnaPClass($pclass)); } } $pclasses->save($this->pcURI); $this->pclasses = $pclasses; } else { throw new Exception('Klarna instance not fully configured!', 50001); } } catch(Exception $e) { $this->pclasses = null; throw new KlarnaException('Error in ' . __METHOD__ . ': ' . $e->getMessage(), $e->getCode()); } } /** * Removes the stored PClasses, if you need to update them. * * @throws KlarnaException * @return void */ public function clearPClasses() { if($this->config instanceof ArrayAccess) { $pclasses = $this->getPCStorage(); $pclasses->clear($this->pcURI); } else { throw new KlarnaException('Error in ' . __METHOD__ . ': Klarna instance not fully configured!', 50001); } } /** * Retrieves the specified PClasses. * * <b>Type can be</b>:<br> * {@link KlarnaPClass::CAMPAIGN}<br> * {@link KlarnaPClass::ACCOUNT}<br> * {@link KlarnaPClass::SPECIAL}<br> * {@link KlarnaPClass::FIXED}<br> * {@link KlarnaPClass::DELAY}<br> * {@link KlarnaPClass::MOBILE}<br> * * @param int $type PClass type identifier. * @throws KlarnaException * @return array An array of PClasses. [KlarnaPClass] */ public function getPClasses($type = null) { try { if(!($this->config instanceof ArrayAccess)) { throw new Exception('Klarna instance not fully configured!', 50001); } if(!$this->pclasses) { $this->pclasses = $this->getPCStorage(); $this->pclasses->load($this->pcURI); } $tmp = $this->pclasses->getPClasses($this->eid, $this->country, $type); $this->sortPClasses($tmp[$this->eid]); return $tmp[$this->eid]; } catch(Exception $e) { throw new KlarnaException('Error in ' . __METHOD__ . ': ' . $e->getMessage(), $e->getCode()); } } /** * Returns the specified PClass. * * @param int $id The PClass ID. * @return KlarnaPClass */ public function getPClass($id) { try { if(!is_numeric($id)) { throw new Exception('Argument id is not an integer!', 50055); } else if(!is_int($id)) { $id = intval($id); } if(!($this->config instanceof ArrayAccess)) { throw new Exception('Klarna instance not fully configured!', 50001); } if(!$this->pclasses || !($this->pclasses instanceof PCStorage)) { $this->pclasses = $this->getPCStorage(); $this->pclasses->load($this->pcURI); } return $this->pclasses->getPClass($id, $this->eid, $this->country); } catch(Exception $e) { throw new KlarnaException('Error in ' . __METHOD__ . ': ' . $e->getMessage(), $e->getCode()); } } /** * Sorts the specified array of KlarnaPClasses. * * @param array &$array An array of {@link KlarnaPClass PClasses}. * @return void */ public function sortPClasses(&$array) { if(!is_array($array)) { //Input is not an array! $array = array(); return; } //Sort pclasses array after natural sort (natcmp) if(!function_exists('pc_cmp')) { function pc_cmp($a, $b) { if($a->getDescription() == null && $b->getDescription() == null) { return 0; } else if($a->getDescription() == null) { return 1; } else if($b->getDescription() == null) { return -1; } else if($b->getType() === 2 && $a->getType() !== 2) { return 1; } else if($b->getType() !== 2 && $a->getType() === 2) { return -1; } return strnatcmp($a->getDescription(), $b->getDescription())*-1; } } usort($array, "pc_cmp"); } /** * Returns the cheapest, per month, PClass related to the specified sum. * * <b>Note</b>: This choose the cheapest PClass for the current country.<br> * {@link Klarna::setCountry()} * * <b>Flags can be</b>:<br> * {@link KlarnaFlags::CHECKOUT_PAGE}<br> * {@link KlarnaFlags::PRODUCT_PAGE}<br> * * @param float $sum The product cost, or total sum of the cart. * @param int $flags Which type of page the info will be displayed on. * @throws KlarnaException * @return KlarnaPClass or false if none was found. */ public function getCheapestPClass($sum, $flags) { if (!is_numeric ($sum)) { throw new KlarnaException( 'Error in ' . __METHOD__ . ': Argument sum is not numeric!'); } if(!is_numeric ($flags) || !in_array ($flags, array(KlarnaFlags::CHECKOUT_PAGE, KlarnaFlags::PRODUCT_PAGE))) { throw new KlarnaException( 'Error in ' . __METHOD__ . ': Flags argument invalid!'); } $lowest_pp = $lowest = false; foreach($this->getPClasses() as $pclass) { $lowest_payment = KlarnaCalc::get_lowest_payment_for_account($pclass->getCountry()); if($pclass->getType() < 2 && $sum >= $pclass->getMinAmount()) { $minpay = KlarnaCalc::calc_monthly_cost($sum, $pclass, $flags); if($minpay < $lowest_pp || $lowest_pp === false) { if($pclass->getType() == KlarnaPClass::ACCOUNT || $minpay >= $lowest_payment) { $lowest_pp = $minpay; $lowest = $pclass; } } } } return $lowest; } /** * Initializes the checkoutHTML objects. * * @see Klarna::checkoutHTML() * @return void */ protected function initCheckout() { $dir = dirname(__FILE__); //Require the CheckoutHTML interface/abstract class require_once($dir.'/checkout/checkouthtml.intf.php'); //Iterate over all .class.php files in checkout/ foreach(glob($dir.'/checkout/*.class.php') as $checkout) { if(!self::$debug) ob_start(); include_once($checkout); $className = basename($checkout, '.class.php'); $cObj = new $className; if($cObj instanceof CheckoutHTML) { $cObj->init($this, $this->eid); $this->coObjects[$className] = $cObj; } if(!self::$debug) ob_end_clean(); } } /** * Returns the checkout page HTML from the checkout classes. * * <b>Note</b>:<br> * This method uses output buffering to silence unwanted echoes.<br> * * @see CheckoutHTML * * @return string A HTML string. */ public function checkoutHTML() { if(empty($this->coObjects)) { $this->initCheckout(); } $dir = dirname(__FILE__); //Require the CheckoutHTML interface/abstract class require_once($dir.'/checkout/checkouthtml.intf.php'); //Iterate over all .class.php files in $html = "\n"; foreach($this->coObjects as $cObj) { if(!self::$debug) ob_start(); if($cObj instanceof CheckoutHTML) { $html .= $cObj->toHTML() . "\n"; } if(!self::$debug) ob_end_clean(); } return $html; } /** * Creates a XMLRPC call with specified XMLRPC method and parameters from array. * * @ignore Do not show this in PHPDoc. * @param string $method XMLRPC method. * @param array $array XMLRPC parameters. * @throws KlarnaException * @return mixed */ protected function xmlrpc_call($method, $array) { try { if(!($this->xmlrpc instanceof xmlrpc_client)) { throw new Exception('Klarna instance not fully configured!', 50001); } if(!isset($method) || !is_string($method)) { throw new Exception("Argument 'method' not a string!", 50066); } if(!$array || count($array) === 0) { throw new Exception("Array empty or null!", 50067); } if(self::$disableXMLRPC) { return true; } /* * Disable verifypeer for CURL, so below error is avoided. * CURL error: SSL certificate problem, verify that the CA cert is OK. * Details: error:14090086:SSL routines:SSL3_GET_SERVER_CERTIFICATE:certificate verify failed (#8) */ $this->xmlrpc->verifypeer = false; $timestart = microtime(true); //Create the XMLRPC message. $msg = new xmlrpcmsg($method); $params = array_merge(array($this->PROTO, $this->VERSION), $array); $msg = new xmlrpcmsg($method); foreach($params as $p) { if(!$msg->addParam(php_xmlrpc_encode($p, array('extension_api')))) { throw new Exception("Failed to add parameters to XMLRPC message.", 50068); } } //Send the message. $selectDateTime = microtime(true); if(self::$xmlrpcDebug) $this->xmlrpc->setDebug(2); $xmlrpcresp = $this->xmlrpc->send($msg); //Calculate time and selectTime. $timeend = microtime(true); $time = (int) (($selectDateTime - $timestart) * 1000); $selectTime = (int) (($timeend - $timestart) * 1000); $status = $xmlrpcresp->faultCode(); //Send report to candice. if(self::$candice === true) { $this->sendStat($method, $time, $selectTime, $status); } if($status !== 0) { throw new KlarnaException($xmlrpcresp->faultString(), $status); } return php_xmlrpc_decode($xmlrpcresp->value()); } catch(KlarnaException $e) { //Otherwise it is catched below, and error in, is prepended. throw $e; } catch(Exception $e) { throw new KlarnaException('Error in ' . __METHOD__ . ': ' . $e->getMessage(), $e->getCode()); } } /** * Removes all relevant order/customer data from the internal structure. * * @return void */ public function clear() { $this->goodsList = null; $this->comment = ""; $this->billing = null; $this->shipping = null; $this->shipInfo = array(); $this->extraInfo = array(); $this->bankInfo = array(); $this->incomeInfo = array(); $this->reference = ""; $this->reference_code = ""; $this->orderid[0] = ""; $this->orderid[1] = ""; $this->artNos = array(); $this->coObjects = array(); } /** * Sends a report to Candice. * * @ignore Do not show this in PHPDoc. * @param string $function XMLRPC method. * @param int $time Elapsed time of entire XMLRPC call. * @param int $selectTime Time to create the XMLRPC parameters. * @param int $status XMLRPC error code. * @return void */ protected function sendStat($method, $time, $selectTime, $status) { if(($fp = @fsockopen('udp://'.self::$c_addr, 80, $errno, $errstr, 1500))) { $url = (($this->ssl) ? 'https://' : 'http://').$this->addr; $data = $this->pipe($this->eid, $method, $time, $selectTime, $status, $url.':'.$this->port); $digest = self::digest($this->pipe($data, $this->secret)); self::printDebug("candice report", $data); @fwrite($fp, $this->pipe($data, $digest)); @fclose($fp); } } /** * Implodes parameters with delimiter ':'. * * @param mixed $field1 Data to be separated by colons. * @param mixed $field2 More data. * @param mixed $field3 More data.. * @param mixed $... More data... * @return string Colon separated string. */ public static function colon(/* variable parameters */) { $args = func_get_args(); return implode(':', $args); } /** * Implodes parameters with delimiter '|'. * * @param mixed $field1 Data to be piped together. * @param mixed $field2 More data. * @param mixed $field3 More data.. * @param mixed $... More data... * @return string Pipe separated string. */ public static function pipe(/* variable parameters */) { $args = func_get_args(); return implode('|', $args); } /** * Creates a digest hash from the inputted string, * and the specified or the preferred hash algorithm. * * @param string $data Data to be hashed. * @throws KlarnaException * @return string Base64 encoded hash. */ public static function digest($data, $hash = null) { if($hash===null) { $preferred = array( 'sha512', 'sha384', 'sha256', 'sha224', 'md5' ); $hashes = array_intersect($preferred, hash_algos()); if(count($hashes) == 0) { throw new KlarnaException("Error in " . __METHOD__ . ": No available hash algorithm supported!"); } $hash = array_shift($hashes); } self::printDebug(__METHOD__.' using hash', $hash); return base64_encode(pack("H*", hash($hash, $data))); } /** * Converts special characters to numeric htmlentities. * * <b>Note</b>:<br> * If supplied string is encoded with UTF-8, o umlaut ("�") will become two HTML entities instead of one. * * @param string $str String to be converted. * @return string String converted to numeric HTML entities. */ public static function num_htmlentities($str) { if(!self::$htmlentities) { self::$htmlentities = array(); foreach(get_html_translation_table(HTML_ENTITIES, ENT_QUOTES) as $char => $entity) { self::$htmlentities[$entity] = '&#' . ord($char) . ';'; } } return str_replace(array_keys(self::$htmlentities), self::$htmlentities, htmlentities($str)); } /** * Prints debug information if debug is set to true. * $msg is used as header/footer in the output. * * if FirePHP is available it will be used instead of * dumping the debug info into the document. * * It uses print_r and encapsulates it in HTML/XML comments. * (<!-- -->) * * @param string $msg Debug identifier, e.g. "my array". * @param mixed $mixed Object, type, etc, to be debugged. * @return void */ public static function printDebug($msg, $mixed) { if(self::$debug) { if(class_exists('FB', false)) { FB::send($mixed, $msg); } else { echo "\n<!-- ".$msg.": \n"; print_r($mixed); echo "\n end ".$msg." -->\n"; } } } /** * Checks/fixes so the invNo input is valid. * * @param string &$invNo Invoice number. * @param string $method __METHOD__ * @throws KlarnaException * @return void */ private function checkInvNo(&$invNo, $method) { if(!isset($invNo)) { throw new KlarnaException("Error in " . $method . ": Invoice number not set!", 50055); } if(!is_string($invNo)) { $invNo = strval($invNo); } if(strlen($invNo) == 0) { throw new KlarnaException("Error in " . $method . ": Invoice number not set!", 50056); } } /** * Checks/fixes so the quantity input is valid. * * @param int &$qty Quantity. * @param string $method __METHOD__ * @throws KlarnaException * @return void */ private function checkQty(&$qty, $method) { if(!isset($qty)) { throw new KlarnaException("Error in " . $method . ": Quantity is not set!", 50057); } if(is_numeric($qty) && !is_int($qty)) { $qty = intval($qty); } if(!is_int($qty)) { throw new KlarnaException("Error in " . $method . ": Quantity is not an integer! ($qty)", 50058); } } /** * Checks/fixes so the artTitle input is valid. * * @param string &$artTitle Article title. * @param string $method __METHOD__ * @throws KlarnaException * @return void */ private function checkArtTitle(&$artTitle, $method) { if(!is_string($artTitle)) { $artTitle = strval($artTitle); } if(!isset($artTitle) || strlen($artTitle) == 0) { throw new KlarnaException("Error in " . $method . ": No artTitle specified!", 50059); } } /** * Checks/fixes so the artNo input is valid. * * @param int|string &$artNo Article number. * @param string $method __METHOD__ * @throws KlarnaException * @return void */ private function checkArtNo(&$artNo, $method) { if(is_numeric($artNo) && !is_string($artNo)) { //Convert artNo to string if integer. $artNo = strval($artNo); } if(!isset($artNo) || strlen($artNo) == 0 || (!is_string($artNo))) { throw new KlarnaException("Error in " . $method . ": No artNo specified! ($artNo)", 50060); } } /** * Checks/fixes so the credNo input is valid. * * @param string &$credNo Credit number. * @param string $method __METHOD__ * @throws KlarnaException * @return void */ private function checkCredNo(&$credNo, $method) { if(!isset($credNo)) { throw new KlarnaException("Error in " . $method . ": Credit number not set!", 50061); } if($credNo === false || $credNo === null) { $credNo = ""; } if(!is_string($credNo)) { $credNo = strval($credNo); if(!is_string($credNo)) { throw new KlarnaException("Error in " . $method . ": Credit number couldn't be converted to string! ($credNo)", 50062); } } } /** * Checks so that artNos is an array and is not empty. * * @param array &$artNos Array from {@link Klarna::addArtNo()}. * @param string $method __METHOD__ * @throws KlarnaException * @return void */ private function checkArtNos(&$artNos, $method) { if(!is_array($artNos)) { throw new KlarnaException("Error in " . $method . ": No artNos array specified!", 50063); } if(empty($artNos)) { throw new KlarnaException('Error in ' . $method . ': ArtNo array is empty!', 50064); } } /** * Checks/fixes so the integer input is valid. * * @param int &$int {@link KlarnaFlags flags} constant. * @param string $field Name of the field. * @param string $method __METHOD__ * @throws KlarnaException * @return void */ private function checkInt(&$int, $field, $method) { if(!isset($int)) { throw new KlarnaException("Error in " . $method . ": $field is not set!", 50065); } if(is_numeric($int) && !is_int($int)) { $int = intval($int); } if(!is_numeric($int) || !is_int($int)) { throw new KlarnaException("Error in " . $method . ": $field not an integer! ($int)", 50066); } } /** * Checks/fixes so the VAT input is valid. * * @param float &$vat VAT. * @param string $method __METHOD__ * @throws KlarnaException * @return void */ private function checkVAT(&$vat, $method) { if(!isset($vat)) { throw new KlarnaException("Error in " . $method . ": VAT is not set!", 50067); } if(is_numeric($vat) && (!is_int($vat) || !is_float($vat))) { $vat = floatval($vat); } if(!is_numeric($vat) || (!is_int($vat) && !is_float($vat))) { throw new KlarnaException("Error in " . $method . ": VAT not an integer or float! ($vat)", 50068); } } /** * Checks/fixes so the amount input is valid. * * @param int &$amount Amount. * @param string $method __METHOD__ * @throws KlarnaException * @return void */ private function checkAmount(&$amount, $method) { if(!isset($amount)) { throw new KlarnaException("Error in " . $method . ": Amount not set!", 50069); } if(is_numeric($amount)) { $this->fixValue($amount); } if(is_numeric($amount) && !is_int($amount)) { $amount = intval($amount); } if(!is_numeric($amount) || !is_int($amount)) { throw new KlarnaException("Error in " . $method . ": Amount not an integer! ($amount)", 50070); } } /** * Checks/fixes so the price input is valid. * * @param int &$price Price. * @param string $method __METHOD__ * @throws KlarnaException * @return void */ private function checkPrice(&$price, $method) { if(!isset($price)) { throw new KlarnaException("Error in " . $method . ": Price is not set!", 50071); } if(is_numeric($price)) { $this->fixValue($price); } if(is_numeric($price) && !is_int($price)) { $price = intval($price); } if(!is_numeric($price) || !is_int($price)) { throw new KlarnaException("Error in " . $method . ": Price not an integer! ($price)", 50072); } } /** * Multiplies value with 100 and rounds it. * This fixes value/price/amount inputs so that KO can handle them. * * @param float &$value * @return void */ private function fixValue(&$value) { $value = round($value * 100); } /** * Checks/fixes so the discount input is valid. * * @param float &$discount Discount amount. * @param string $method __METHOD__ * @throws KlarnaException * @return void */ private function checkDiscount(&$discount, $method) { if(!isset($discount)) { throw new KlarnaException("Error in " . $method . ": Discount is not set!", 50073); } if(is_numeric($discount) && (!is_int($discount) || !is_float($discount))) { $discount = floatval($discount); } if(!is_numeric($discount) || (!is_int($discount) && !is_float($discount))) { throw new KlarnaException("Error in " . $method . ": Discount not an integer or float! ($discount)", 50074); } } /** * Checks/fixes so that the estoreOrderNo input is valid. * * @param string &$estoreOrderNo Estores order number. * @param string $method __METHOD__ * @throws KlarnaException * @return void */ private function checkEstoreOrderNo(&$estoreOrderNo, $method) { if(!isset($estoreOrderNo)) { throw new KlarnaException("Error in " . $method . ": Order number not set!", 50075); } if(!is_string($estoreOrderNo)) { $estoreOrderNo = strval($estoreOrderNo); if(!is_string($estoreOrderNo)) { throw new KlarnaException("Error in " . $method . ": Order number couldn't be converted to string! ($estoreOrderNo)", 50076); } } } /** * Checks/fixes to the PNO/SSN input is valid. * * @param string &$pno Personal number, social security number, ... * @param int $enc {@link KlarnaEncoding PNO Encoding} constant. * @param string $method __METHOD__ * @throws KlarnaException * @return void */ private function checkPNO(&$pno, $enc, $method) { if(!$pno) { throw new KlarnaException("Error in " . $method . ": PNO/SSN not set for customer or given as a parameter!", 50077); } if(!KlarnaEncoding::checkPNO($pno, $enc)) { throw new KlarnaException("Error in " . $method . ": PNO/SSN is not valid!", 50078); } } /** * Checks/fixes to the country input is valid. * * @param int &$country {@link KlarnaCountry Country} constant. * @param string $method __METHOD__ * @throws KlarnaException * @return void */ private function checkCountry(&$country, $method) { if(!isset($country)) { throw new KlarnaException("Error in " . $method . ": Country argument not set!", 50079); } if(is_numeric($country) && !is_int($country)) { $country = intval($country); } if(!is_numeric($country) || !is_int($country)) { throw new KlarnaException("Error in " . $method . ": Country must be an integer! ($country)", 50080); } } /** * Checks/fixes to the language input is valid. * * @param int &$language {@link KlarnaLanguage Language} constant. * @param string $method __METHOD__ * @throws KlarnaException * @return void */ private function checkLanguage(&$language, $method) { if(!isset($language)) { throw new KlarnaException("Error in " . $method . ": Language argument not set!", 50081); } if(is_numeric($language) && !is_int($language)) { $language = intval($language); } if(!is_numeric($language) || !is_int($language)) { throw new KlarnaException("Error in " . $method . ": Language must be an integer! ($language)", 50082); } } /** * Checks/fixes to the currency input is valid. * * @param int &$currency {@link KlarnaCurrency Currency} constant. * @param string $method __METHOD__ * @throws KlarnaException * @return void */ private function checkCurrency(&$currency, $method) { if(!isset($currency)) { throw new KlarnaException("Error in " . $method . ": Currency argument not set!", 50083); } if(is_numeric($currency) && !is_int($currency)) { $currency = intval($currency); } if(!is_numeric($currency) || !is_int($currency)) { throw new KlarnaException("Error in " . $method . ": Currency must be an integer! ($currency)", 50084); } } /** * Checks/fixes so no/number is a valid input. * * @param int &$no Number. * @param string $method __METHOD__ * @throws KlarnaException * @return void */ private function checkNo(&$no, $method) { if(!isset($no)) { throw new KlarnaException("Error in " . $method . ": Argument no not set!", 50085); } if(is_numeric($no) && !is_int($no)) { $no = intval($no); } if(!is_numeric($no) || !is_int($no) || $no <= 0) { throw new KlarnaException("Error in " . $method . ": Argument no must be an integer and above 0! ($no)", 50086); } } /** * Checks/fixes so reservation number is a valid input. * * @param string &$rno Reservation number. * @param string $method __METHOD__ * @throws KlarnaException * @return void */ private function checkRNO(&$rno, $method) { if(!is_string($rno)) { $rno = strval($rno); } if(strlen($rno) == 0) { throw new KlarnaException("Error in " . $method . ": RNO isn't set!", 50087); } } /** * Checks/fixes so that reference/refCode are valid. * * @param string &$reference Reference string. * @param string &$refCode Reference code. * @param string $method __METHOD__ * @throws KlarnaException * @return void */ private function checkRef(&$reference, &$refCode, $method) { if(!is_string($reference)) { $reference = strval($reference); if(!is_string($reference)) { throw new KlarnaException("Error in " . $method . ": Reference couldn't be converted to string! ($reference)", 50088); } } if(!is_string($refCode)) { $refCode = strval($refCode); if(!is_string($refCode)) { throw new KlarnaException("Error in " . $method . ": Reference code couldn't be converted to string! ($refCode)", 50089); } } } /** * Checks/fixes so that the OCR input is valid. * * @param string &$ocr OCR number. * @param string $method __METHOD__ * @throws KlarnaException * @return void */ private function checkOCR(&$ocr, $method) { if(!is_string($ocr)) { $ocr = strval($ocr); if(!is_string($ocr)) { throw new KlarnaException("Error in " . $method . ": OCR couldn't be converted to string or isn't a string! ($ocr)", 50090); } } } } //End Klarna /** * Provides encoding constants. * * @package KlarnaAPI */ class KlarnaEncoding { /** * PNO/SSN encoding for Sweden. * * @var int */ const PNO_SE = 2; /** * PNO/SSN encoding for Norway. * * @var int */ const PNO_NO = 3; /** * PNO/SSN encoding for Finland. * * @var int */ const PNO_FI = 4; /** * PNO/SSN encoding for Denmark. * * @var int */ const PNO_DK = 5; /** * PNO/SSN encoding for Germany. * * @var int */ const PNO_DE = 6; /** * PNO/SSN encoding for Netherlands. * * @var int */ const PNO_NL = 7; /** * Encoding constant for customer numbers. * * @see Klarna::setCustomerNo() * @var int */ const CUSTNO = 1000; /** * Encoding constant for email address. * * @var int */ const EMAIL = 1001; /** * Encoding constant for cell numbers. * * @var int */ const CELLNO = 1002; /** * Encoding constant for bank bic + account number. * * @var int */ const BANK_BIC_ACC_NO = 1003; /** * Returns a regexp string for the specified encoding constant. * * @param int $enc PNO/SSN encoding constant. * @return string The regular expression. * @throws KlarnaException */ public static function getRegexp($enc) { switch($enc) { /** * All positions except C contain numbers 0-9. * * PNO: * YYYYMMDDCNNNN, C = -|+ length 13 * YYYYMMDDNNNN 12 * YYMMDDCNNNN 11 * YYMMDDNNNN 10 * * ORGNO: * XXXXXXNNNN * XXXXXX-NNNN * 16XXXXXXNNNN * 16XXXXXX-NNNN * */ case self::PNO_SE: return '/^[0-9]{6,6}(([0-9]{2,2}[-\+]{1,1}[0-9]{4,4})|([-\+]{1,1}[0-9]{4,4})|([0-9]{4,6}))$/'; break; /** * All positions contain numbers 0-9. * * Pno * DDMMYYIIIKK ("fodelsenummer" or "D-nummer") length = 11 * DDMMYY-IIIKK ("fodelsenummer" or "D-nummer") length = 12 * DDMMYYYYIIIKK ("fodelsenummer" or "D-nummer") length = 13 * DDMMYYYY-IIIKK ("fodelsenummer" or "D-nummer") length = 14 * * Orgno * Starts with 8 or 9. * * NNNNNNNNK (orgno) length = 9 */ case self::PNO_NO: return '/^[0-9]{6,6}((-[0-9]{5,5})|([0-9]{2,2}((-[0-9]{5,5})|([0-9]{1,1})|([0-9]{3,3})|([0-9]{5,5))))$/'; break; /** * Pno * DDMMYYCIIIT * DDMMYYIIIT * C = century, '+' = 1800, '-' = 1900 och 'A' = 2000. * I = 0-9 * T = 0-9, A-F, H, J, K-N, P, R-Y * * Orgno * NNNNNNN-T * NNNNNNNT * T = 0-9, A-F, H, J, K-N, P, R-Y */ case self::PNO_FI: return '/^[0-9]{6,6}(([A\+-]{1,1}[0-9]{3,3}[0-9A-FHJK-NPR-Y]{1,1})|([0-9]{3,3}[0-9A-FHJK-NPR-Y]{1,1})|([0-9]{1,1}-{0,1}[0-9A-FHJK-NPR-Y]{1,1}))$/i'; break; /** * Pno * DDMMYYNNNG length 10 * G = gender, odd/even for men/women. * * Orgno * XXXXXXXX length 8 */ case self::PNO_DK: return '/^[0-9]{8,8}([0-9]{2,2})?$/'; break; /** * Pno * DDMMYYYYG length 9 * DDMMYYYY 8 * * Orgno * XXXXXXX 7 company org nr */ case self::PNO_NL: case self::PNO_DE: return '/^[0-9]{7,9}$/'; break; /** * Validates an email. */ case self::EMAIL: return '/^[_a-zA-Z0-9-]+(\.[_a-zA-Z0-9-]+)*@[a-zA-Z0-9-]+(\.[a-zA-Z0-9-]+)*(\.[a-zA-Z0-9-][a-zA-Z0-9-]+)+$/'; break; /** * Validates a cellno. * */ case self::CELLNO: return '/^07[\ \-0-9]{8,13}$/'; break; default: throw new KlarnaException('Error in ' . __METHOD__ . ': Unknown PNO/SSN encoding constant! ('.$enc.')', 50091); } } /** * Checks if the specified PNO is correct according to specified encoding constant. * * @param string $pno PNO/SSN string. * @param int $enc {@link KlarnaEncoding PNO/SSN encoding} constant. * @return bool True if correct. * @throws KlarnaException */ public static function checkPNO($pno, $enc) { $regexp = self::getRegexp($enc); if($regexp === false) { return true; } else { return (preg_match($regexp, $pno)) ? true : false; } } /** * Class constructor. * Disable instantiation. */ private function __construct() { } } //End KlarnaEncoding /** * Provides flags/constants used for various methods. * * @package KlarnaAPI */ class KlarnaFlags { /** * Specifies that no flag is to be used. * * @var int */ const NO_FLAG = 0; //Gender flags /** * Indicates that the person is a female.<br> * Use "" or null when unspecified.<br> * * @var int */ const FEMALE = 0; /** * Indicates that the person is a male.<br> * Use "" or null when unspecified.<br> * * @var int */ const MALE = 1; //Order status constants /** * This signifies that the invoice or reservation is accepted. * * @var int */ const ACCEPTED = 1; /** * This signifies that the invoice or reservation is pending, will be set to accepted or denied. * * @var int */ const PENDING = 2; /** * This signifies that the invoice or reservation is <b>denied</b>. * * @var int */ const DENIED = 3; //Get_address constants /** * A code which indicates that all first names should be returned with the address.<br> * * Formerly refered to as GA_OLD. * * @var int */ const GA_ALL = 1; /** * A code which indicates that only the last name should be returned with the address.<br> * * Formerly referd to as GA_NEW. * * @var int */ const GA_LAST = 2; /** * A code which indicates that the given name should be returned with the address. * If no given name is registered, this will behave as {@link KlarnaFlags::GA_ALL GA_ALL}. * */ const GA_GIVEN = 5; //Article/goods constants /** * Quantity measured in 1/1000s. * * @var int */ const PRINT_1000 = 1; /** * Quantity measured in 1/100s. * * @var int */ const PRINT_100 = 2; /** * Quantity measured in 1/10s. * * @var int */ const PRINT_10 = 4; /** * Indicates that the item is a shipment fee. * * Update_charge_amount (1) * * @var int */ const IS_SHIPMENT = 8; /** * Indicates that the item is a handling fee. * * Update_charge_amount (2) * * @var int */ const IS_HANDLING = 16; /** * Article price including VAT. * * @var int */ const INC_VAT = 32; //Miscellaneous /** * Signifies that this is to be displayed in the checkout.<br> * Used for part payment.<br> * * @var int */ const CHECKOUT_PAGE = 0; /** * Signifies that this is to be displayed in the product page.<br> * Used for part payment.<br> * * @var int */ const PRODUCT_PAGE = 1; /** * Signifies that the specified address is billing address. * * @var int */ const IS_BILLING = 100; /** * Signifies that the specified address is shipping address. * * @var int */ const IS_SHIPPING = 101; //Invoice and Reservation /** * Indicates that the purchase is a test invoice/part payment. * * @var int */ const TEST_MODE = 2; /** * PClass id/value for invoices. * * @see KlarnaPClass::INVOICE. * @var int */ const PCLASS_INVOICE = -1; //Invoice /** * Activates an invoices automatically, requires setting in Klarna Online. * * If you designate this flag an invoice is created directly in the active state, * i.e. Klarna will buy the invoice immediately. * * @var int */ const AUTO_ACTIVATE = 1; /** * Creates a pre-pay invoice. * * @var int */ const PRE_PAY = 8; /** * Used to flag a purchase as sensitive order. * * @var int */ const SENSITIVE_ORDER = 1024; /** * Used to return an array with long and short ocr number. * * @see Klarna::addTransaction() * @var int */ const RETURN_OCR = 8192; /** * Specifies the shipment type as normal. * * @var int */ const NORMAL_SHIPMENT = 1; /** * Specifies the shipment type as express. * * @var int */ const EXPRESS_SHIPMENT = 2; //Mobile (Invoice) flags /** * Marks the transaction as Klarna mobile. * * @var int */ const M_PHONE_TRANSACTION = 262144; /** * Sends a pin code to the phone sent in pno. * * @var int */ const M_SEND_PHONE_PIN = 524288; //Reservation flags /** * Signifies that the amount specified is the new amount. * * @var int */ const NEW_AMOUNT = 0; /** * Signifies that the amount specified is to be added. * * @var int */ const ADD_AMOUNT = 1; /** * Sends the invoice by mail when activating a reservation. * * @var int */ const RSRV_SEND_BY_MAIL = 4; /** * Sends the invoice by e-mail when activating a reservation. * * @var int */ const RSRV_SEND_BY_EMAIL = 8; /** * Used for partial deliveries, this flag saves the reservation number so it can be used again. * * @var int */ const RSRV_PRESERVE_RESERVATION = 16; /** * Used to flag a purchase as sensitive order. * * @var int */ const RSRV_SENSITIVE_ORDER = 32; /** * Marks the transaction as Klarna mobile. * * @var int */ const RSRV_PHONE_TRANSACTION = 512; /** * Sends a pin code to the mobile number. * * @var int */ const RSRV_SEND_PHONE_PIN = 1024; /** * Class constructor. * Disable instantiation. */ private function __construct() { } } /** * Provides currency constants for the supported countries. * * @package KlarnaAPI */ class KlarnaCurrency { /** * Currency constant for Swedish Crowns (SEK). * * @var int */ const SEK = 0; /** * Currency constant for Norwegian Crowns (NOK). * * @var int */ const NOK = 1; /** * Currency constant for Euro. * * @var int */ const EUR = 2; /** * Currency constant for Danish Crowns (DKK). * * @var int */ const DKK = 3; /** * Class constructor. * Disable instantiation. */ private function __construct() { } /** * Converts a currency code, e.g. 'eur' to the KlarnaCurrency constant. * * @param string $val * @return int|null */ public static function fromCode($val) { switch(strtolower($val)) { case 'dkk': return self::DKK; case 'eur': case 'euro': return self::EUR; case 'nok': return self::NOK; case 'sek': return self::SEK; default: return null; } } /** * Converts a KlarnaCurrency constant to the respective language code. * * @param int $val * @return string|null */ public static function getCode($val) { switch($val) { case self::DKK: return 'dkk'; case self::EUR: return 'eur'; case self::NOK: return 'nok'; case self::SEK: return 'sek'; default: return null; } } } //End KlarnaCurrency /** * Provides language constants (ISO639) for the supported countries. * * @package KlarnaAPI */ class KlarnaLanguage { /** * Language constant for Danish (DA).<br> * ISO639_DA * * @var int */ const DA = 27; /** * Language constant for German (DE).<br> * ISO639_DE * * @var int */ const DE = 28; /** * Language constant for English (EN).<br> * ISO639_EN * * @var int */ const EN = 31; /** * Language constant for Finnish (FI).<br> * ISO639_FI * * @var int */ const FI = 37; /** * Language constant for Norwegian (NB).<br> * ISO639_NB * * @var int */ const NB = 97; /** * Language constant for Dutch (NL).<br> * ISO639_NL * * @var int */ const NL = 101; /** * Language constant for Swedish (SV).<br> * ISO639_SV * * @var int */ const SV = 138; /** * Class constructor. * Disable instantiation. */ private function __construct() { } /** * Converts a language code, e.g. 'de' to the KlarnaLanguage constant. * * @param string $val * @return int|null */ public static function fromCode($val) { switch(strtolower($val)) { case 'en': return self::EN; case 'da': return self::DA; case 'de': return self::DE; case 'fi': return self::FI; case 'nb': return self::NB; case 'nl': return self::NL; case 'sv': return self::SV; default: return null; } } /** * Converts a KlarnaLanguage constant to the respective language code. * * @param int $val * @return string|null */ public static function getCode($val) { switch($val) { case self::EN: return 'en'; case self::DA: return 'da'; case self::DE: return 'de'; case self::FI: return 'fi'; case self::NB: return 'nb'; case self::NL: return 'nl'; case self::SV: return 'sv'; default: return null; } } } //End KlarnaLanguage /** * Provides country constants (ISO3166) for the supported countries. * * @package KlarnaAPI */ class KlarnaCountry { /** * Country constant for Denmark (DK).<br> * ISO3166_DK * * @var int */ const DK = 59; /** * Country constant for Finland (FI).<br> * ISO3166_FI * * @var int */ const FI = 73; /** * Country constant for Germany (DE).<br> * ISO3166_DE * * @var int */ const DE = 81; /** * Country constant for Netherlands (NL).<br> * ISO3166_NL * * @var int */ const NL = 154; /** * Country constant for Norway (NO).<br> * ISO3166_NO * * @var int */ const NO = 164; /** * Country constant for Sweden (SE).<br> * ISO3166_SE * * @var int */ const SE = 209; /** * Class constructor. * Disable instantiation. */ private function __construct() { } /** * Converts a country code, e.g. 'de' or 'deu' to the KlarnaCountry constant. * * @param string $val * @return int|null */ public static function fromCode($val) { switch(strtolower($val)) { case 'swe': case 'se': return self::SE; case 'nor': case 'no': return self::NO; case 'dnk': case 'dk': return self::DK; case 'fin': case 'fi': return self::FI; case 'deu': case 'de': return self::DE; case 'nld': case 'nl': return self::NL; default: return null; } } /** * Converts a KlarnaCountry constant to the respective country code. * * @param int $val * @param bool $alpha3 Whether to return a ISO-3166-1 alpha-3 code * @return string|null */ public static function getCode($val, $alpha3 = false) { switch($val) { case KlarnaCountry::SE: return ($alpha3) ? 'swe' : 'se'; case KlarnaCountry::NO: return ($alpha3) ? 'nor' : 'no'; case KlarnaCountry::DK: return ($alpha3) ? 'dnk' : 'dk'; case KlarnaCountry::FI: return ($alpha3) ? 'fin' : 'fi'; case KlarnaCountry::DE: return ($alpha3) ? 'deu' : 'de'; case self::NL: return ($alpha3) ? 'nld' : 'nl'; default: return null; } } } //End KlarnaCountry /** * KlarnaException class, only used so it says "KlarnaException" instead of Exception. * * @package KlarnaAPI */ class KlarnaException extends Exception { /** * Returns an error message readable by end customers. * * @return string */ public function __toString() { //API error codes if($this->code >= 50000) { $message = $this->getMessage(); return $message . " (#".$this->code.")"; } else { //KO error codes return $this->getMessage() . " (#".$this->code.")"; } } } /** * Include the {@link KlarnaConfig} class. */ //require_once('klarnaconfig.php'); /** * Include the {@link KlarnaPClass} class. */ //require_once('klarnapclass.php'); /** * Include the {@link KlarnaCalc} class. */ //require_once('klarnacalc.php'); /** * Include the {@link KlarnaAddr} class. */ //require_once('klarnaaddr.php');