@@ -144,6 +144,46 @@ protected function createResponse($data)
144144 return $ this ->response = new Response ($ this , $ data );
145145 }
146146
147+ /**
148+ * Filters out any characters that SagePay does not support from the item name.
149+ *
150+ * Believe it or not, SagePay actually have separate rules for allowed characters
151+ * for item names and discount names, hence the need for two separate methods.
152+ *
153+ * @param string $name
154+ *
155+ * @return string
156+ */
157+ protected function filterItemName ($ name )
158+ {
159+ $ standardChars = "0-9a-zA-Z " ;
160+ $ allowedSpecialChars = " +'/ \\&:,.-{} " ;
161+ $ pattern = '`[^ ' .$ standardChars .preg_quote ($ allowedSpecialChars , '/ ' ).']` ' ;
162+ $ name = trim (substr (preg_replace ($ pattern , '' , $ name ), 0 , 100 ));
163+
164+ return $ name ;
165+ }
166+
167+ /**
168+ * Filters out any characters that SagePay does not support from the discount name.
169+ *
170+ * Believe it or not, SagePay actually have separate rules for allowed characters
171+ * for item names and discount names, hence the need for two separate methods.
172+ *
173+ * @param string $name
174+ *
175+ * @return string
176+ */
177+ protected function filterDiscountName ($ name )
178+ {
179+ $ standardChars = "0-9a-zA-Z " ;
180+ $ allowedSpecialChars = " +'/ \\:,.-{};_@()^ \"~[]$=!#?| " ;
181+ $ pattern = '`[^ ' .$ standardChars .preg_quote ($ allowedSpecialChars , '/ ' ).']` ' ;
182+ $ name = trim (substr (preg_replace ($ pattern , '' , $ name ), 0 , 100 ));
183+
184+ return $ name ;
185+ }
186+
147187 /**
148188 * Get an XML representation of the current cart items
149189 *
@@ -160,27 +200,33 @@ protected function getItemData()
160200 }
161201
162202 $ xml = new \SimpleXMLElement ('<basket/> ' );
203+ $ cartHasDiscounts = false ;
163204
164205 foreach ($ items as $ basketItem ) {
165206 if ($ basketItem ->getPrice () < 0 ) {
166- $ discounts = $ xml ->addChild ('discounts ' );
167- $ discount = $ discounts ->addChild ('discount ' );
168- $ discount ->addChild ('fixed ' , $ basketItem ->getPrice () * -1 );
169- $ discount ->addChild ('description ' , $ basketItem ->getName ());
207+ $ cartHasDiscounts = true ;
170208 } else {
171209 $ total = ($ basketItem ->getQuantity () * $ basketItem ->getPrice ());
172210 $ item = $ xml ->addChild ('item ' );
173- $ item ->addChild ( ' description ' , $ basketItem ->getName ());
211+ $ item ->description = $ this -> filterItemName ( $ basketItem ->getName ());
174212 $ item ->addChild ('quantity ' , $ basketItem ->getQuantity ());
175213 $ item ->addChild ('unitNetAmount ' , $ basketItem ->getPrice ());
176214 $ item ->addChild ('unitTaxAmount ' , '0.00 ' );
177215 $ item ->addChild ('unitGrossAmount ' , $ basketItem ->getPrice ());
178216 $ item ->addChild ('totalGrossAmount ' , $ total );
179217 }
180218 }
181-
219+ if ($ cartHasDiscounts ) {
220+ $ discounts = $ xml ->addChild ('discounts ' );
221+ foreach ($ items as $ discountItem ) {
222+ if ($ discountItem ->getPrice () < 0 ) {
223+ $ discount = $ discounts ->addChild ('discount ' );
224+ $ discount ->addChild ('fixed ' , ($ discountItem ->getPrice () * $ discountItem ->getQuantity ()) * -1 );
225+ $ discount ->description = $ this ->filterDiscountName ($ discountItem ->getName ());
226+ }
227+ }
228+ }
182229 $ xmlString = $ xml ->asXML ();
183-
184230 if ($ xmlString ) {
185231 $ result = $ xmlString ;
186232 }
0 commit comments