Skip to content

Commit eb21a99

Browse files
committed
first commit, interface is still untested some additional documentation is needed
0 parents  commit eb21a99

10 files changed

+857
-0
lines changed

LICENSE

+27
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
Copyright (c) 2011, Mikko Forsström, Mikko Hirvonen, Eevert Saukkokoski
2+
All rights reserved.
3+
4+
Redistribution and use in source and binary forms, with or without
5+
modification, are permitted provided that the following conditions are met:
6+
7+
* Redistributions of source code must retain the above copyright
8+
notice, this list of conditions and the following disclaimer.
9+
10+
* Redistributions in binary form must reproduce the above copyright
11+
notice, this list of conditions and the following disclaimer in the
12+
documentation and/or other materials provided with the distribution.
13+
14+
* Neither the names of the authors nor the names of contributors may be used
15+
to endorse or promote products derived from this software without specific
16+
prior written permission.
17+
18+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
19+
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20+
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21+
DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT,
22+
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23+
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
24+
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
25+
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
26+
OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
27+
ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

README

Whitespace-only changes.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
<?php
2+
namespace Xi\Netvisor\Zend\Exception;
3+
4+
/**
5+
* Netvisor responce status exception
6+
*
7+
* @category Xi
8+
* @package Netvisor
9+
* @subpackage Zend
10+
* @author Panu Leppäniemi <me@panuleppaniemi.com>
11+
* @author Henri Vesala <henri.vesala@gmail.fi>
12+
*/
13+
class NetvisorResponseStatusException extends \Zend_Service_Exception
14+
{
15+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
<?php
2+
namespace Xi\Netvisor\Zend\Exception;
3+
4+
/**
5+
* Xml validation exception for invalid xml.
6+
* automatically creates error message validation error array
7+
*
8+
* @category Xi
9+
* @package Netvisor
10+
* @subpackage Zend
11+
* @author Henri Vesala <henri.vesala@gmail.fi>
12+
*/
13+
class XmlValidationException extends \Zend_Exception
14+
{
15+
private $xmlValidationErrors;
16+
17+
/**
18+
* creates new validation error exception
19+
*
20+
* @param array $validationErrors
21+
*/
22+
public function __construct($validationErrors) {
23+
$this->xmlValidationErrors = $validationErrors;
24+
parent::__construct($this->createErrorMessage($validationErrors));
25+
}
26+
27+
/**
28+
* creates error message from validation error array
29+
*
30+
* @param array $validationErrors
31+
* @return string
32+
*/
33+
private function createErrorMessage($validationErrors)
34+
{
35+
$errorMessage = "Xml Validation errors: \n";
36+
foreach($validationErrors as $errorline) {
37+
foreach($errorline as $errorName => $errors) {
38+
$errorMessage.= "$errorName: ".implode(', ',$errors)."\n";
39+
}
40+
}
41+
return $errorMessage;
42+
}
43+
}

library/Xi/Netvisor/Zend/Netvisor.php

+171
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,171 @@
1+
<?php
2+
namespace Xi\Netvisor\Zend;
3+
4+
/**
5+
*
6+
* connects to netvisor and sends them invoice xml.
7+
*
8+
* @category Xi
9+
* @package Netvisor
10+
* @subpackage Zend
11+
* @author Panu Leppäniemi <me@panuleppaniemi.com>
12+
* @author Henri Vesala <henri.vesala@gmail.fi>
13+
*/
14+
class Netvisor extends \Zend_Rest_Client
15+
{
16+
const METHOD_ADD = 'add',
17+
METHOD_EDIT = 'edit?id=';
18+
19+
const SERVICE_INVOICE_SALES = 'salesinvoice';
20+
21+
const RESPONSE_STATUS_OK = 'OK',
22+
RESPONSE_STATUS_FAILED = 'FAILED';
23+
24+
/**
25+
* @var Zend_Http_Client
26+
*/
27+
private $client = null;
28+
29+
/**
30+
* @var Zend_Http_Config
31+
*/
32+
private $config = null;
33+
34+
35+
public function __construct()
36+
{
37+
$this->config = $this->_getConfig();
38+
39+
$this->client = new \Zend_Http_Client(
40+
$this->config->interface->host,
41+
array('maxdirects' => 0, 'timeout' => 30, 'keepalive' => true)
42+
);
43+
}
44+
45+
/**
46+
* Sends an invoice to Netvisor.
47+
*
48+
* @param string $xml
49+
* @return Zend_Rest_Client_Result
50+
*/
51+
public function addInvoice($xml)
52+
{
53+
return $this->_request($xml, self::SERVICE_INVOICE_SALES);
54+
}
55+
56+
/**
57+
* Edits an invoice that already exists in Netvisor.
58+
*
59+
* @param string $xml
60+
* @return Zend_Rest_Client_Result
61+
*/
62+
public function editInvoice($id, $xml)
63+
{
64+
return $this->_request($xml, self::SERVICE_INVOICE_SALES, self::METHOD_EDIT . $id);
65+
}
66+
67+
/**
68+
* Makes a request to Netvisor and returns a response.
69+
*
70+
* @param string $xml
71+
* @param string $service
72+
* @param string $method
73+
* @return Zend_Rest_Client_Result
74+
*/
75+
private function _request($xml, $service, $method = self::METHOD_ADD)
76+
{
77+
if(!$this->config->interface->enabled) {
78+
return null;
79+
}
80+
81+
$timestamp = \DateTime::createFromFormat('U.u', microtime(true));
82+
$timestamp->setTimezone(new \DateTimeZone('GMT'));
83+
$time = substr($timestamp->format('Y-m-d H:i:s.u'),0,-3);
84+
85+
86+
$url = "{$this->config->interface->host}/{$service}.nv?method={$method}";
87+
88+
// Reset the client.
89+
$this->client->resetParameters(true);
90+
91+
// Start building the client.
92+
$this->client->setUri($url);
93+
94+
$authenticationTransactionId = $this->getAuthenticationTransactionId();
95+
96+
// Set headers which Netvisor demands.
97+
$this->client->setHeaders(array(
98+
'X-Netvisor-Authentication-Sender' => $this->config->interface->sender,
99+
'X-Netvisor-Authentication-CustomerId' => $this->config->interface->customerId,
100+
'X-Netvisor-Authentication-PartnerId' => $this->config->interface->partnerId,
101+
'X-Netvisor-Authentication-Timestamp' => $time,
102+
'X-Netvisor-Interface-Language' => $this->config->interface->language,
103+
'X-Netvisor-Authentication-Organisation-ID' => $this->config->interface->organizationId,
104+
'X-Netvisor-Authentication-TransactionId' => $authenticationTransactionId,
105+
'X-Netvisor-Authentication-MAC' => $this->_getAuthenticationMac($service, $time, $authenticationTransactionId),
106+
107+
));
108+
109+
// Attach XML to the request.
110+
$this->client->setRawData($xml, 'text/xml');
111+
112+
try {
113+
$result = new \Zend_Rest_Client_Result($this->client->request('POST')->getBody());
114+
115+
if(strstr($result->ResponseStatus->Status[0], self::RESPONSE_STATUS_FAILED)) {
116+
throw new Exception\NetvisorResponseStatusException($result->ResponseStatus->Status[1]);
117+
}
118+
119+
return $result;
120+
} catch(\Zend_Http_Client_Exception $e) {
121+
throw $e;
122+
} catch(\Exception $e) {
123+
throw $e;
124+
}
125+
}
126+
127+
/**
128+
* Calculates MAC MD5-hash for headers.
129+
*
130+
* @param string $service
131+
* @param DateTime $timestamp
132+
* @param string $authenticationTransactionId
133+
* @return string
134+
*/
135+
private function _getAuthenticationMac($service, $time, $authenticationTransactionId)
136+
{
137+
$parameters = array(
138+
"{$this->config->interface->host}/{$service}.nv",
139+
$this->config->interface->sender,
140+
$this->config->interface->customerId,
141+
$time,
142+
$this->config->interface->language,
143+
$this->config->interface->organizationId,
144+
$authenticationTransactionId,
145+
$this->config->interface->userKey,
146+
$this->config->interface->partnerKey,
147+
);
148+
149+
return md5(implode('&', $parameters));
150+
}
151+
152+
/**
153+
* generates unique transaction id
154+
*
155+
* @return string
156+
*/
157+
private function getAuthenticationTransactionId()
158+
{
159+
return rand(1000,9999).microtime();
160+
}
161+
162+
163+
/**
164+
* @return Zend_Config
165+
*/
166+
private function _getConfig()
167+
{
168+
return \Zend_Registry::get('config')->netvisor;
169+
}
170+
171+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
<?php
2+
namespace Xi\Netvisor\Zend\Validate;
3+
/**
4+
* Validate ANSI Date format
5+
*
6+
7+
* @category Xi
8+
* @package Netvisor
9+
* @subpackage Zend
10+
* @author Henri Vesala <henri.vesala@gmail.com>
11+
*/
12+
class AnsiDate extends \Zend_Validate_Abstract
13+
{
14+
const INVALID_DATE = 'dateInvalidDate';
15+
const FALSEFORMAT = 'dateFalseFormat';
16+
17+
/**
18+
* Validation failure message template definitions
19+
*
20+
* @var array
21+
*/
22+
protected $_messageTemplates = array(
23+
self::INVALID_DATE => "'%value%' does not appear to be a valid date",
24+
self::FALSEFORMAT => "'%value%' does not fit the ANSI date format 'yyyy-mm-dd'",
25+
);
26+
27+
/**
28+
* Check if $value is a valid date and valid ANSI format (yyyy-mm-dd)
29+
*
30+
* @param string $value
31+
* @return bool
32+
*/
33+
public function isValid($value)
34+
{
35+
$this->_setValue($value);
36+
37+
if (!preg_match('#^\d{4}-\d{2}-\d{2}$#', $value)) {
38+
$this->_error(self::FALSEFORMAT);
39+
40+
return false;
41+
}
42+
43+
list($year, $month, $day) = sscanf($value, '%d-%d-%d');
44+
45+
if (!checkdate($month, $day, $year)) {
46+
$this->_error(self::INVALID_DATE);
47+
48+
return false;
49+
}
50+
51+
return true;
52+
}
53+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
<?php
2+
namespace Xi\Netvisor\Zend\Validate;
3+
4+
/**
5+
* Validate transaction reference number
6+
*
7+
* @category Xi
8+
* @package Netvisor
9+
* @subpackage Zend
10+
* @author Henri Vesala <henri.vesala@gmail.com>
11+
*/
12+
class TransactionReferenceNumber extends \Zend_Validate_Abstract
13+
{
14+
const NOTNUMERIC = 'transactionReferenceNumberNotNumeric';
15+
const TOOLONG = 'transactionReferenceNumberTooLong';
16+
const INVALIDCHECKSUM = 'transactionReferenceNumberChecksumm';
17+
18+
/**
19+
* Validation failure message template definitions
20+
*
21+
* @var array
22+
*/
23+
protected $_messageTemplates = array(
24+
self::NOTNUMERIC => "'%value%' is not valid numeric transaction reference number.",
25+
self::TOOLONG => "'%value%' is not valid transaction reference number. Number is too long.",
26+
self::INVALIDCHECKSUM => "'%value%' is not valid transaction reference number. Invalid checksum.",
27+
);
28+
29+
/**
30+
* validates transaction reference number
31+
*
32+
* @param string $value
33+
* @return bool
34+
*/
35+
public function isValid($value)
36+
{
37+
$this->_setValue($value);
38+
39+
if(!is_numeric($value)){
40+
$this->_error(self::NOTNUMERIC);
41+
return false;
42+
}
43+
44+
$checkDigit = $value % 10;
45+
$value = $value.''; // as string
46+
47+
if(strlen($value) > 20) {
48+
$this->_error(self::TOOLONG);
49+
return false;
50+
}
51+
52+
$multipliers = array('7','3','1');
53+
54+
55+
56+
$sum = 0;
57+
for($i = 0; $i < strlen($value) -1; $i++) {
58+
$sum += $value[$i]*$multipliers[$i%3];
59+
}
60+
61+
$calcCheckDigit = $sum % 10;
62+
if($calcCheckDigit){
63+
$calcCheckDigit = 10 - $calcCheckDigit;
64+
}
65+
66+
if($checkDigit != $calcCheckDigit){
67+
$this->_error(self::INVALIDCHECKSUM);
68+
return false;
69+
}
70+
return true;
71+
72+
}
73+
}

0 commit comments

Comments
 (0)