Magento - adding custom attribute to extended core Customer module - magento-1.4

hi have to add a custom attribute to the Customer. so i've extended the core Customer module, these are files involved and directory tree:
//app/code/local/Nauba/etc/config.xml
<?xml version="1.0"?>
<config>
<modules>
<Nauba_Customer>
<version>0.0.1</version>
</Nauba_Customer>
</modules>
<global>
<models>
<customer>
<rewrite>
<customer>Nauba_Customer_Model_Customer</customer>
</rewrite>
</customer>
</models>
</global>
</config>
// app/code/local/Nauba/Customer/Model/Customer.php
class Nauba_Customer_Model_Customer extends Mage_Customer_Model_Customer
{
function _construct()
{
parent::__construct();
}
}
// app/etc/modules/Nauba_Customer.xml
<?xml version="1.0"?>
<config>
<modules>
<Nauba_Customer>
<active>true</active>
<codePool>local</codePool>
</Nauba_Customer>
</modules>
</config>
//app/code/local/Nauba/Customer/sql/nauba_customer_setup/mysql4-upgrade-1.6.2.0.2-1.6.2.0.3.php
$installer = $this;
$installer->startSetup();
/**
* Adding custom attributes to customer
*/
$installer->addAttribute('customer', 'elite_invitation', array(
'label' => 'ID prodotto invito Elite',
'type' => 'varchar',
'visible' => true,
'visible_on_front' => false,
'required' => false,
'backend' => '',
'frontend' => '',
'input' => 'text',
'global' => Mage_Catalog_Model_Resource_Eav_Attribute::SCOPE_WEBSITE
));
$installer->endSetup();
Now the module is enabled and new custom model is used instead of core Mage_Customer, but sql upgrade is not executed. any idea of what is wrong?
thanx luke

you must define "resources" in xml under global
<resources>
<nauba_customer_setup>
<setup>
<module>your module name</module>
</setup>
</nauba_customer_setup>
</resources>

Related

Can't specify header in SOAP call using Savon

When calling to an API for retrieving labels for post parcels I get frustrated with how hard it is to set up a SOAP call with ruby.
I know that the following works from a sandbox environment:
this is the SHOULD BE call
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
<s:Header>
<Action s:mustUnderstand="1" xmlns="http://schemas.microsoft.com/ws/2005/05/addressing/none">http://postnl.nl/cif/services/BarcodeWebService/IBarcodeWebService/GenerateBarcode</Action>
<Security xmlns="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
<wsse:UsernameToken xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
<wsse:Username>devc_!R4xc8p9</wsse:Username>
<wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText">098fd559930983af31ef6630a0bb0c1974156561</wsse:Password>
</wsse:UsernameToken>
</Security>
</s:Header>
<s:Body>
<GenerateBarcode xmlns:d6p1="http://postnl.nl/cif/domain/BarcodeWebService/" xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://postnl.nl/cif/services/BarcodeWebService/">
<d6p1:Message>
<d6p1:MessageID>5</d6p1:MessageID>
<d6p1:MessageTimeStamp>28-06-2017 14:15:41</d6p1:MessageTimeStamp>
</d6p1:Message>
<d6p1:Customer>
<d6p1:CustomerCode>DEVC</d6p1:CustomerCode>
<d6p1:CustomerNumber>11223344</d6p1:CustomerNumber>
</d6p1:Customer>
<d6p1:Barcode>
<d6p1:Type>3S</d6p1:Type>
<d6p1:Range>DEVC</d6p1:Range>
<d6p1:Serie>1000000-2000000</d6p1:Serie>
</d6p1:Barcode>
</GenerateBarcode>
</s:Body>
</s:Envelope>
EDIT
As sugested I used build_request to inspect how my request looks. It actually looks like this:
<?xml version="1.0" encoding="UTF-8"?>
<env:Envelope xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:wsdl="http://tempuri.org/" xmlns:env="http://schemas.xmlsoap.org/soap/envelope/">
<env:Header>
<Username>devc_!R4xc8p9</Username
<Password>098fd559930983af31ef6630a0bb0c1974156561</Password>
</env:Header>
<env:Body><wsdl:GenerateBarcode><CustomerCode>DEVC</CustomerCode>
<CustomerNumber>11223344</CustomerNumber>
<Type>3S</Type>
<Range>DEVC</Range>
<Serie>1000000-2000000</Serie>
</wsdl:GenerateBarcode>
</env:Body>
</env:Envelope>
Comparing that with the xml above, it becomes clear that stuff is off. How to handle nesting?
This is when I build it myself like:
#client = Savon.client(
:convert_request_keys_to => :camelcase,
:raise_errors => false,
:pretty_print_xml => true,
:wsdl => 'https://testservice.postnl.com/CIF_SB/BarcodeWebService/1_1/?wsdl',
:headers => {
'Username' => 'devc_!R4xc8p9',
'Password' => '098fd559930983af31ef6630a0bb0c1974156561'
})
#response = #client.call(:generate_barcode) do
soap_header "Username" => 'devc_!R4xc8p9',
"Password" => '098fd559930983af31ef6630a0bb0c1974156561'
message customer_code: 'DEVC',
customer_number: 11223344,
type: '3S',
range: 'DEVC',
serie: '1000000-2000000'
end
I know my connection works, but also get back:
{:fault=>{:faultcode=>"s:CIF Framework Message Interceptor",
:faultstring=>"Check CIFException in the detail section", :detail=>
{:cif_exception=>{:errors=>{:exception_data=>{:description=>nil,
:error_msg=>"Username/password is not specified.",
:error_number=>"3"}},
:#xmlns=>"http://postnl.nl/cif/services/common/",
:"#xmlns:i"=>"http://www.w3.org/2001/XMLSchema-instance"}}}}
So already in my header stuff goes wrong. Username/password is not specified. I've tried several combinations and I don't get why.
Update
#client = Savon.client(
:env_namespace => :s,
# :namespace_identifier => :none, # :none doesn't work... gets interpreted literary. Out-commeting gives wsdl:GenerateBarcode
:convert_request_keys_to => :camelcase,
:raise_errors => false,
:pretty_print_xml => true,
:endpoint => 'https://testservice.postnl.com/CIF_SB/BarcodeWebService/1_1/BarcodeWebService.svc',
:wsdl => 'https://testservice.postnl.com/CIF_SB/BarcodeWebService/1_1/?wsdl')
soap_header = {
"Security" => {
"UsernameToken" => {
"Username" => 'devc_!R4xc8p9',
"Password" => '098fd559930983af31ef6630a0bb0c1974156561'
}
}
}
message = {
"d6p1:Customer" => {
"d6p1:CustomerCode" => 'DEVC',
"d6p1:CustomerNumber" => 11223344
},
"d6p1:Barcode" => {
"d6p1:Type" => '3S',
"d6p1:Range" => 'DEVC',
"d6p1:Serie" => '1000000-2000000'
}
}
#request = #client.build_request(:generate_barcode) do
soap_header soap_header
message message
end
#response = #client.call(:generate_barcode) do
soap_header soap_header
message message
Which builds the following request:
<?xml version="1.0" encoding="UTF-8"?>
<s:Envelope xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:s="http://tempuri.org/" xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
<s:Header>
<Security>
<UsernameToken>
<Username>devc_!R4xc8p9</Username
<Password>098fd559930983af31ef6630a0bb0c1974156561</Password>
</UsernameToken>
</Security>
</s:Header>
<s:Body>
<wsdl:GenerateBarcode>
<d6p1:Customer>
<d6p1:CustomerCode>DEVC</d6p1:CustomerCode
<d6p1:CustomerNumber>11223344</d6p1:CustomerNumber>
</d6p1:Customer>
<d6p1:Barcode>
<d6p1:Type>3S</d6p1:Type>
<d6p1:Range>DEVC</d6p1:Range>
<d6p1:Serie>1000000-2000000</d6p1:Serie>
</d6p1:Barcode></s:GenerateBarcode>
</s:Body>
For as of yet, I get errors adding the wsse: namespace straight in the soap_header hash.
EDIT 2
<?xml version="1.0" encoding="UTF-8"?>
<s:Envelope
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:wsdl="http://tempuri.org/"
xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
<s:Header>
<Action s:mustUnderstand="1" xmlns="http://schemas.microsoft.com/ws/2005/05/addressing/none">http://postnl.nl/cif/services/BarcodeWebService/IBarcodeWebService/GenerateBarcode
</Action>
<Security xmlns="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
<UsernameToken>
<Username>devc_!R4xc8p9</Username>
<Password>xxxxxxxx</Password>
</UsernameToken>
</Security>
</s:Header>
<s:Body>
<wsdl:GenerateBarcode>
<d6p1:Customer>
<d6p1:CustomerCode>DEVC</d6p1:CustomerCode>
<d6p1:CustomerNumber>11223344</d6p1:CustomerNumber>
</d6p1:Customer>
<d6p1:Barcode>
<d6p1:Type>3S</d6p1:Type>
<d6p1:Range>DEVC</d6p1:Range>
<d6p1:Serie>1000000-2000000</d6p1:Serie>
</d6p1:Barcode>
</wsdl:GenerateBarcode>
</s:Body>
</s:Envelope>
Comparing this to my should be call it seems that my <s:envelope ...> tag has too much information.
I'll make a follow up question of this probably.
EDIT 3
I restarted at Complex SOAP call in Ruby on Rails using Savon gets weird around the envelope and main operation
The Message hash, should be nested in the same way as the call expects it something like
#client = Savon.client(
:convert_request_keys_to => :camelcase,
:raise_errors => false,
:pretty_print_xml => true,
:wsdl => 'https://testservice.postnl.com/CIF_SB/BarcodeWebService/1_1/?wsdl',
:headers => {
'Username' => 'devc_!R4xc8p9',
'Password' => '098fd559930983af31ef6630a0bb0c1974156561'
})
#response = #client.call(:generate_barcode) do
soap_header "Security" => {
"UsernameToken" => {
"Username" => 'devc_!R4xc8p9',
"Password" => '098fd559930983af31ef6630a0bb0c1974156561'
}
}
message "GenerateBarcode" => {
"Message" => {
"MessageID" => 5, #might be different
"MessageTime" => Time.now, #might be different depending on use case
},
"Customer" => {
"CustomerCode" => 'DEVC',
"CustomerNumber" => 11223344
},
"Barcode" => {
"Type" => '3S',
"Range" => 'DEVC',
"Serie" => '1000000-2000000'
}
}
end
EDIT
Referencing this page it looks like you can add the action tag and elements like this
'Action' => "http://postnl.nl/cif/services/BarcodeWebService/IBarcodeWebService/GenerateBarcode",
:attributes! => {
"s:mustUnderstand" => "1",
"xmlns" => "http://schemas.microsoft.com/ws/2005/05/addressing/none"
}
Referencing this page it looks like you can set the namespaces directly "wsse:UsernameToken" instead of "UsernameToken"
which should result in the following
#client = Savon.client(
:convert_request_keys_to => :camelcase,
:raise_errors => false,
:pretty_print_xml => true,
:wsdl => 'https://testservice.postnl.com/CIF_SB/BarcodeWebService/1_1/?wsdl',
:headers => {
'Username' => 'devc_!R4xc8p9',
'Password' => '098fd559930983af31ef6630a0bb0c1974156561'
})
#response = #client.call(:generate_barcode) do
soap_header "Security" => {
"wsse:UsernameToken" => {
"wsse:Username" => 'devc_!R4xc8p9',
"wsse:Password" => '098fd559930983af31ef6630a0bb0c1974156561'
}
"Action" => "http://postnl.nl/cif/services/BarcodeWebService/IBarcodeWebService/GenerateBarcode",
:attributes! => {
"s:mustUnderstand" => "1",
"xmlns" => "http://schemas.microsoft.com/ws/2005/05/addressing/none"
}
}
message "GenerateBarcode" => {
"Message" => {
"MessageID" => 5, #might be different
"MessageTime" => Time.now, #might be different depending on use case
},
"Customer" => {
"CustomerCode" => 'DEVC',
"CustomerNumber" => 11223344
},
"Barcode" => {
"Type" => '3S',
"Range" => 'DEVC',
"Serie" => '1000000-2000000'
}
}
end

How to sign xml with X509Certificate in Ruby?

I'm trying to sign a xml with a X509Certificate, i'm using the signer gem.
private_key_file = File.join(File.dirname(__FILE__), '/cert/1234567890001_priKEY.pem')
cert_file = File.join(File.dirname(__FILE__), '/cert/1234567890001_certKEY.pem')
input_xml_file = File.join(File.dirname(__FILE__), 'nfce_xml.xml')
signer = Signer.new(File.read(input_xml_file))
signer.cert = OpenSSL::X509::Certificate.new(File.read(cert_file))
signer.private_key = OpenSSL::PKey::RSA.new(File.read(private_key_file), "")
signer.security_node = signer.document.root
signer.security_token_id = ""
signer.digest!(signer.document.root, :id => "NFe51150501882109000162650010000000011064552496", :enveloped => true)
signer.sign!(:issuer_serial => true)
signed_xml = signer.to_xml
File.open("signed.xml", 'w') {|f| f.write(signed_xml) }
the signature:
<Signature xmlns="http://www.w3.org/2000/09/xmldsig#">
<SignedInfo>
<CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#" />
<SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1" />
<Reference URI="#NFe51150501882109000162650010000000011064552496">
<Transforms>
<Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature" />
</Transforms>
<DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1" />
<DigestValue>xgvKmWBZeQSt0vue30DzzBvc494=</DigestValue>
</Reference>
</SignedInfo>
<SignatureValue>DE8BKKsxBAh/zEnX/N/P0f/xOZD7O...</SignatureValue>
<KeyInfo>
<X509Data>
<X509IssuerSerial>
<X509IssuerName>System.Security.Cryptography.X509Certificates.X500DistinguishedName</X509IssuerName>
<X509SerialNumber>2701224559233645315</X509SerialNumber>
</X509IssuerSerial>
<X509Certificate>MIIIHzCCBgegAwIBAgIIJXytbMe...</X509Certificate>
</X509Data>
</KeyInfo>
</Signature>
but i need remove the X509IssuerSerial tag, add this transform:
<Transform Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315" />
and also change CanonicalizationMethod to:
<CanonicalizationMethod Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315" />
Someone can help?
Thanks.
There is not much you can do about format.
Captain obvious suggests to disable issuer_serial in signer.sign!(:issuer_serial => true) to remove the X509IssuerSerial tag?

ZF2 An Invalid Factory Was Registered

I've the following classes and my module config in ZF2 application and it is giving the below error:
While attempting to create applicationformuserform(alias: Application\Form
\UserForm) an invalid factory was registered for this instance type.
UserFormFactory.php
<?php
namespace Application\Factory\Form;
use Zend\ServiceManager\FactoryInterface;
use Zend\ServiceManager\ServiceLocatorInterface;
use Application\Form\UserForm;
class UserFormFactory implements FactoryInterface {
public function createService(ServiceLocatorInterface $serviceLocator) {
$services = $serviceLocator->getServiceLocator();
$entityManager = $services->get('Doctrine\ORM\EntityManager');
$form = new UserForm($entityManager);
return $form;
}
}
?>
UserForm.php
<?php
namespace Application\Form;
use Zend\Form\Form;
use Zend\InputFilter\InputFilterProviderInterface;
use Doctrine\ORM\EntityManager;
class UserForm extends Form implements InputFilterProviderInterface {
protected $entityManager;
public function __construct(EntityManager $entityManager) {
parent::__construct();
$this->entityManager = $entityManager;
}
public function init() {
$this->add(array(
'name' => 'username',
'attributes' => array(
'type' => 'text',
),
'options' => array(
'label' => 'User Name',
),
));
$this->add(array(
'name' => 'first_name',
'attributes' => array(
'type' => 'text',
),
'options' => array(
'label' => 'First Name',
),
));
$this->add(array(
'name' => 'last_name',
'attributes' => array(
'type' => 'text',
),
'options' => array(
'label' => 'Last Name',
),
));
$this->add(array(
'name' => 'role_id',
'type' => 'DoctrineModule\Form\Element\ObjectSelect',
'options' => array(
'object_manager' => $this->entityManager,
'target_class' => 'Application\Entity\Role',
'property' => 'id',
'is_method' => true,
'find_method' => array(
'name' => 'getRoles',
),
'label' => 'User Role',
),
));
}
public function getInputFilterSpecification() {
return array(); // filter and validation here
}
}
?>
Module.config.php
'form_elements' => array(
'factories' => array(
'Application\Form\UserForm' => 'Application\Factory\Form\UserFormFactory',
),
),
And I'm using this form factory in another controller factory
UserControllerFactory.php
<?php
namespace Member\Factory\Controller;
use Zend\ServiceManager\FactoryInterface;
use Zend\ServiceManager\ServiceLocatorInterface;
use Member\Controller\UserController;
use Application\Form\UserForm;
class UserControllerFactory implements FactoryInterface {
public function createService(ServiceLocatorInterface $serviceLocator) {
$services = $serviceLocator->getServiceLocator();
$userForm = $services->get('FormElementManager')->get('Application\Form\UserForm');
$controller = new UserController($userForm);
return $controller;
}
}
?>
Could anybody tell me that what may be the issue?
Your Factory is not being found.
Check if you using PSR-4 or PSR-0 in your controller among the other answers
Briefly
did you name the Factory correctly (no misspellings)?
Is your composer.json updated with PSR-0, or PSR-4 namespaces for your modules?
did you run composer dump-autoload?
Does your autoload_classmap.php contain an outdated entry & confuses autoloader?
Check your folder structure and names
make sure your Factory implements FactoryInterface
Ask yourself "Why is my Factory class not being found when I have placed it right there" where it obviously without a doubt must be found? That will help you guide your way into finding out what's wrong.
I got my answer at my own after looking at the code again and again. Actually my Factory and Form folders were outside of src folder that's why Zend could not found all the classes of both folders.
I moved both Factory and Form folder in src and now it's working fine.
I had a similar problem. I had made some changes to my factory classes (refactoring + minor class name changes). Turns out that because I was using the Classmap Autoloader ... and forgot to re-run php vendor/bin/classmap_generator.php in the module structure ... the newly renamed classes were not found. Too bad a "class not found" error wasn't generated.

How do I create this element using Nokogiri builder?

I have an element in my XML but I am not sure how to get it generated in Nokogiri::XML::Builder.
<ns0:SearchCondition expressionLanguage='String'expressionType='PartyNumber'>31955854</ns0:SearchCondition>
I tried this:
def test_xml
builder = Nokogiri::XML::Builder.new do |xml|
xml.root {
xml.products {
xml.widget {
xml.id_ "10"
xml.name "Awesome widget"
xml.SearchCondition('expressionLanguage' => 'String', 'expressionType' => 'PartyNumber')
}
}
}
end
puts builder.to_xml
This produces the following
<?xml version="1.0"?>
<root>
<products>
<widget>
<id>10</id>
<name>Awesome widget</name>
<SearchCondition expressionLanguage="String" expressionType="PartyNumber"/>
</widget>
</products>
</root>
But I am not sure how I pass the value to the PartyNumber.
Not sure if this is what you are asking, but you can use the builder text method to create a text element inside another:
xml.SearchCondition('expressionLanguage' => 'String', 'expressionType' => 'PartyNumber') {
xml.text "31955854"
}
You're not using the namespace in your example, but you don't mention that, so I guess that is not an issue.

Global and module config interaction

Let's imagine I have global application configuration
return array(
'languages' => array(
'allowed' => array('de', 'en'),
),
);
And I have module configuration with the routes description. I need routes, based on global configuration, so I need to read global application config within the module to compose my routes according to languages->allowed values (constraints for the segment type route)
What is the best way to get global configuration values from the module configuration script? is it correct at all to manipulate data in configuration file instead of simple array return?
You should think a bit more ahead of your problem. You want to create a route structure based on your configuration. The configuration could come from everywhere: module config, local config and global config. It is therefore quite hard to base your module's config on a global one.
What you can do, is create the routes later. For example, you create in your module Foo the config like this:
'routes_foo' => array(
'bar' => array(
'type' => 'segment',
'options' => array(
'route' => ':locale/foo/bar',
'constraints' => array(
'locale' => '%LOCALE%',
),
),
),
),
And in your module class:
namespace Foo;
class Module
{
public function onBootstrap($e)
{
$app = $e->getApplication();
$sm = $app->getServiceManager();
$config = $sm->get('config');
$routes = $config['routes_foo');
$locales = $config['languages']['allowed'];
$routes = $this->replace($routes, array(
'%LOCALE%' => sprintf('(%s)', implode('|', $locales)
);
$router = $sm->get('router');
$router->routeFromArray($routes);
}
public function replace($array, $variables)
{
foreach ($array as $key => $value) {
if (is_array($value)) {
$array[$name] = $this->replace($value, $variables);
}
if (array_key_exists($value, $variables)) {
$array[$name] = $variables[$value];
}
}
return $array;
}
}
What happens is you grab the routes from your config (those are not automatically injected in the router). There you also load all languages from your global config. Then your "custom" routes have (at several places) a "magic" configuration key, which will be replaced by a regex constraint for the locales: (en|de). That parsed config is then injected into the router.

Resources