diff --git a/CHANGELOG.md b/CHANGELOG.md
index 77afe65225a..13d463c0178 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,12 @@
+CHANGELOG for 1.0.0-rc2
+===================
+This changelog references the relevant changes (new features, changes and bugs) done in 1.0.0-rc2 versions.
+
+* 1.0.0-rc2 (2014-02-25)
+ * Refactored Flexible Workflows
+ * Embedded forms
+ * Account merging
+
CHANGELOG for 1.0.0-rc1
===================
This changelog references the relevant changes (new features, changes and bugs) done in 1.0.0-rc1 versions.
diff --git a/UPGRADE.md b/UPGRADE.md
index 2e6d9433e50..77e78634e2f 100644
--- a/UPGRADE.md
+++ b/UPGRADE.md
@@ -1,3 +1,45 @@
+UPGRADE to 1.0.0-RC2 from 1.0.0-RC1
+=======================
+
+### General
+
+ * Pull changes from repository
+```bash
+git pull
+```
+ * Upgrade composer dependency
+```bash
+php composer.phar update --prefer-dist
+```
+ * Remove old caches
+```bash
+rm -rf app/cache/*
+```
+ * Fix extended entities configuration by executing below queries in mysql console.
+
+delete FROM oro_entity_config_value where code = 'schema' and field_id is not null;
+delete FROM oro_entity_config_value where field_id in (select id FROM oro_entity_config_field where field_name like 'field_%');
+delete FROM oro_entity_config_field where field_name like 'field_%';
+delete FROM oro_entity_config_value where code = 'set_options' and value = 'Array';
+
+ * Update extend entities configuration
+```bash
+php app/console oro:entity-extend:update-config --env=prod
+php app/console oro:entity-extend:dump --env=prod
+```
+ * Upgrade platform
+```bash
+php app/console oro:platform:update --env=prod
+```
+ * Load new fixtures
+```bash
+php app/console oro:installer:fixtures:load --env=prod
+```
+ * Load new workflows definitions
+```bash
+php app/console oro:workflow:definitions:load --env=prod
+```
+
UPGRADE to any 1.0.0-alpha and beta version
=======================
diff --git a/composer.json b/composer.json
index c78fa3d96e9..1946daf963c 100644
--- a/composer.json
+++ b/composer.json
@@ -2,7 +2,7 @@
"name": "oro/crm",
"description": "OroCRM",
"homepage": "https://github.com/orocrm/crm.git",
- "license": "The Open Software License version 3.0",
+ "license": "OSL-3.0",
"authors": [
{
"name": "Oro, Inc",
@@ -16,7 +16,7 @@
},
"require": {
"php": ">=5.4.4",
- "oro/platform": "1.0.0-rc2"
+ "oro/platform": "1.0.0-rc3"
},
"minimum-stability": "dev",
"prefer-stable": true,
diff --git a/src/OroCRM/Bundle/AccountBundle/Entity/Account.php b/src/OroCRM/Bundle/AccountBundle/Entity/Account.php
index ee0acf71a6f..d18d470e2ae 100644
--- a/src/OroCRM/Bundle/AccountBundle/Entity/Account.php
+++ b/src/OroCRM/Bundle/AccountBundle/Entity/Account.php
@@ -16,6 +16,7 @@
use Oro\Bundle\DataAuditBundle\Metadata\Annotation as Oro;
use Oro\Bundle\EntityConfigBundle\Metadata\Annotation\Config;
+use Oro\Bundle\EntityConfigBundle\Metadata\Annotation\ConfigField;
use Oro\Bundle\UserBundle\Entity\User;
@@ -28,7 +29,11 @@
* routeName="orocrm_account_index",
* routeView="orocrm_account_view",
* defaultValues={
- * "entity"={"label"="Account", "plural_label"="Accounts"},
+ * "entity"={
+ * "label"="Account",
+ * "plural_label"="Accounts",
+ * "icon"="icon-suitcase"
+ * },
* "ownership"={
* "owner_type"="USER",
* "owner_field_name"="owner",
@@ -37,6 +42,9 @@
* "security"={
* "type"="ACL",
* "group_name"=""
+ * },
+ * "merge"={
+ * "enable"=true
* }
* }
* )
@@ -57,6 +65,7 @@ class Account extends ExtendAccount implements Taggable
* @ORM\Column(type="string", length=255)
* @Soap\ComplexType("string")
* @Oro\Versioned
+ * @ConfigField(defaultValues={"merge"={"enable"=true}})
*/
protected $name;
@@ -65,6 +74,7 @@ class Account extends ExtendAccount implements Taggable
* @ORM\ManyToOne(targetEntity="Oro\Bundle\UserBundle\Entity\User")
* @ORM\JoinColumn(name="user_owner_id", referencedColumnName="id", onDelete="SET NULL")
* @Soap\ComplexType("string", nillable=true)
+ * @ConfigField(defaultValues={"merge"={"enable"=true}})
*/
protected $owner;
@@ -73,6 +83,7 @@ class Account extends ExtendAccount implements Taggable
*
* @ORM\ManyToOne(targetEntity="Oro\Bundle\AddressBundle\Entity\Address", cascade={"persist", "remove"})
* @ORM\JoinColumn(name="shipping_address_id", referencedColumnName="id", onDelete="SET NULL")
+ * @ConfigField(defaultValues={"merge"={"enable"=true}})
*/
protected $shippingAddress;
@@ -81,6 +92,8 @@ class Account extends ExtendAccount implements Taggable
*
* @ORM\ManyToOne(targetEntity="Oro\Bundle\AddressBundle\Entity\Address", cascade={"persist", "remove"})
* @ORM\JoinColumn(name="billing_address_id", referencedColumnName="id", onDelete="SET NULL")
+ * @ConfigField(defaultValues={"merge"={"enable"=true}})
+ * @ConfigField(defaultValues={"merge"={"enable"=true}})
*/
protected $billingAddress;
@@ -91,6 +104,7 @@ class Account extends ExtendAccount implements Taggable
*
* @ORM\ManyToMany(targetEntity="OroCRM\Bundle\ContactBundle\Entity\Contact", inversedBy="accounts")
* @ORM\JoinTable(name="orocrm_account_to_contact")
+ * @ConfigField(defaultValues={"merge"={"enable"=true}})
*/
protected $contacts;
@@ -101,6 +115,7 @@ class Account extends ExtendAccount implements Taggable
*
* @ORM\ManyToOne(targetEntity="OroCRM\Bundle\ContactBundle\Entity\Contact")
* @ORM\JoinColumn(name="default_contact_id", referencedColumnName="id", onDelete="SET NULL")
+ * @ConfigField(defaultValues={"merge"={"enable"=true}})
*/
protected $defaultContact;
@@ -122,6 +137,7 @@ class Account extends ExtendAccount implements Taggable
/**
* @var ArrayCollection $tags
+ * @ConfigField(defaultValues={"merge"={"enable"=true}})
*/
protected $tags;
@@ -240,6 +256,19 @@ public function addContact(Contact $contact)
return $this;
}
+ /**
+ * Set contacts collection
+ *
+ * @param Collection $contacts
+ * @return Account
+ */
+ public function setContacts(Collection $contacts)
+ {
+ $this->contacts = $contacts;
+
+ return $this;
+ }
+
/**
* Get shipping address
*
@@ -256,7 +285,7 @@ public function getShippingAddress()
* @param Address $address
* @return Account
*/
- public function setShippingAddress(Address $address)
+ public function setShippingAddress($address)
{
$this->shippingAddress = $address;
@@ -279,7 +308,7 @@ public function getBillingAddress()
* @param Address $address
* @return Account
*/
- public function setBillingAddress(Address $address)
+ public function setBillingAddress($address)
{
$this->billingAddress = $address;
@@ -383,6 +412,10 @@ public function setDefaultContact($defaultContact)
{
$this->defaultContact = $defaultContact;
+ if ($defaultContact && !$this->contacts->contains($defaultContact)) {
+ $this->addContact($defaultContact);
+ }
+
return $this;
}
diff --git a/src/OroCRM/Bundle/AccountBundle/Resources/config/datagrid.yml b/src/OroCRM/Bundle/AccountBundle/Resources/config/datagrid.yml
index 132dd414f6b..120cde24c0a 100644
--- a/src/OroCRM/Bundle/AccountBundle/Resources/config/datagrid.yml
+++ b/src/OroCRM/Bundle/AccountBundle/Resources/config/datagrid.yml
@@ -1,7 +1,5 @@
datagrid:
dashboard-my-accounts-activity-grid:
- options:
- entityHint: account
source:
type: orm
acl_resource: orocrm_call_view
@@ -42,6 +40,7 @@ datagrid:
contactPhone:
label: orocrm.contact.contactphone.phone.label
options:
+ entityHint: account
toolbarOptions:
hide: true
pageSize:
@@ -169,8 +168,14 @@ datagrid:
label: Delete
icon: trash
link: delete_link
+ mass_actions:
+ merge:
+ type: merge
+ entity_name: %orocrm_account.account.entity.class%
+ data_identifier: a.id
options:
entityHint: account
+ export: true
base-account-contacts-grid:
extended_entity_name: %orocrm_contact.entity.class%
diff --git a/src/OroCRM/Bundle/AccountBundle/Resources/config/navigation.yml b/src/OroCRM/Bundle/AccountBundle/Resources/config/navigation.yml
index 1d746a6fd4f..3125c35dd8f 100644
--- a/src/OroCRM/Bundle/AccountBundle/Resources/config/navigation.yml
+++ b/src/OroCRM/Bundle/AccountBundle/Resources/config/navigation.yml
@@ -9,6 +9,7 @@ oro_menu_config:
label: orocrm.account.entity_plural_label
route: orocrm_account_index
extras:
+ position: 5
routes: ['orocrm_account_*']
description: List of accounts
diff --git a/src/OroCRM/Bundle/AccountBundle/Resources/config/search.yml b/src/OroCRM/Bundle/AccountBundle/Resources/config/search.yml
index 0ddf7796240..138e3ee1a52 100644
--- a/src/OroCRM/Bundle/AccountBundle/Resources/config/search.yml
+++ b/src/OroCRM/Bundle/AccountBundle/Resources/config/search.yml
@@ -7,7 +7,6 @@ OroCRM\Bundle\AccountBundle\Entity\Account:
parameters:
id: id
search_template: OroCRMAccountBundle:Account:searchResult.html.twig
- entity_icon_class: icon-home
fields:
-
name: name
diff --git a/src/OroCRM/Bundle/AccountBundle/Tests/Functional/API/RestAccountTest.php b/src/OroCRM/Bundle/AccountBundle/Tests/Functional/API/RestAccountTest.php
index b78ee849f49..eb6c54b0025 100644
--- a/src/OroCRM/Bundle/AccountBundle/Tests/Functional/API/RestAccountTest.php
+++ b/src/OroCRM/Bundle/AccountBundle/Tests/Functional/API/RestAccountTest.php
@@ -28,7 +28,11 @@ public function testCreate()
"owner" => '1',
)
);
- $this->client->request('POST', $this->client->generate('oro_api_post_account'), $request);
+ $this->client->request(
+ 'POST',
+ $this->client->generate('oro_api_post_account'),
+ $request
+ );
$result = $this->client->getResponse();
ToolsAPI::assertJsonResponse($result, 201);
$result = ToolsAPI::jsonToArray($result->getContent());
@@ -45,7 +49,10 @@ public function testCreate()
*/
public function testGet($request)
{
- $this->client->request('GET', $this->client->generate('oro_api_get_accounts'));
+ $this->client->request(
+ 'GET',
+ $this->client->generate('oro_api_get_accounts')
+ );
$result = $this->client->getResponse();
$result = ToolsAPI::jsonToArray($result->getContent());
$id = $request['id'];
@@ -59,7 +66,10 @@ function ($a) use ($id) {
$this->assertNotEmpty($result);
$this->assertEquals($request['account']['name'], reset($result)['name']);
- $this->client->request('GET', $this->client->generate('oro_api_get_account', array('id' => $request['id'])));
+ $this->client->request(
+ 'GET',
+ $this->client->generate('oro_api_get_account', array('id' => $request['id']))
+ );
$result = $this->client->getResponse();
ToolsAPI::assertJsonResponse($result, 200);
@@ -84,7 +94,10 @@ public function testUpdate($request)
ToolsAPI::assertJsonResponse($result, 204);
- $this->client->request('GET', $this->client->generate('oro_api_get_account', array('id' => $request['id'])));
+ $this->client->request(
+ 'GET',
+ $this->client->generate('oro_api_get_account', array('id' => $request['id']))
+ );
$result = $this->client->getResponse();
ToolsAPI::assertJsonResponse($result, 200);
diff --git a/src/OroCRM/Bundle/AccountBundle/Tests/Functional/API/SoapAccountTest.php b/src/OroCRM/Bundle/AccountBundle/Tests/Functional/API/SoapAccountTest.php
index 96998eb83f6..64c7e9fd29a 100644
--- a/src/OroCRM/Bundle/AccountBundle/Tests/Functional/API/SoapAccountTest.php
+++ b/src/OroCRM/Bundle/AccountBundle/Tests/Functional/API/SoapAccountTest.php
@@ -79,8 +79,10 @@ public function testUpdate($request)
$accountUpdate = $request;
unset($accountUpdate['id']);
$accountUpdate['name'] .= '_Updated';
+
$result = $this->client->getSoap()->updateAccount($request['id'], $accountUpdate);
$this->assertTrue($result);
+
$account = $this->client->getSoap()->getAccount($request['id']);
$account = ToolsAPI::classToArray($account);
@@ -92,18 +94,13 @@ public function testUpdate($request)
/**
* @param $request
* @depends testUpdate
- * @throws \Exception|\SoapFault
*/
public function testDelete($request)
{
$result = $this->client->getSoap()->deleteAccount($request['id']);
$this->assertTrue($result);
- try {
- $this->client->getSoap()->getAccount($request['id']);
- } catch (\SoapFault $e) {
- if ($e->faultcode != 'NOT_FOUND') {
- throw $e;
- }
- }
+
+ $this->setExpectedException('\SoapFault', 'Record with ID "' . $request['id'] . '" can not be found');
+ $this->client->getSoap()->getAccount($request['id']);
}
}
diff --git a/src/OroCRM/Bundle/AccountBundle/Tests/Selenium/CreateAccountTest.php b/src/OroCRM/Bundle/AccountBundle/Tests/Selenium/CreateAccountTest.php
index c66c33e2dd0..f3197da1b55 100644
--- a/src/OroCRM/Bundle/AccountBundle/Tests/Selenium/CreateAccountTest.php
+++ b/src/OroCRM/Bundle/AccountBundle/Tests/Selenium/CreateAccountTest.php
@@ -63,7 +63,7 @@ public function testUpdateAccount($accountName)
$newAccountName = 'Update_' . $accountName;
$login = $this->login();
- $login->openAccounts('OroCRM\Bundle\AccountBundle')
+ $login = $login->openAccounts('OroCRM\Bundle\AccountBundle')
->filterBy('Account name', $accountName)
->open(array($accountName))
->edit()
@@ -74,8 +74,7 @@ public function testUpdateAccount($accountName)
->toGrid()
->assertTitle('Accounts - Customers')
->close();
-
- return $newAccountName;
+ return $newAccountName;
}
/**
diff --git a/src/OroCRM/Bundle/CRMBundle/OroCRMBundle.php b/src/OroCRM/Bundle/CRMBundle/OroCRMBundle.php
index a053b68875a..c2d89e01ea5 100644
--- a/src/OroCRM/Bundle/CRMBundle/OroCRMBundle.php
+++ b/src/OroCRM/Bundle/CRMBundle/OroCRMBundle.php
@@ -6,5 +6,5 @@
class OroCRMBundle extends Bundle
{
- const VERSION = '1.0.0-RC1';
+ const VERSION = '1.0.0-RC2';
}
diff --git a/src/OroCRM/Bundle/CallBundle/Entity/Call.php b/src/OroCRM/Bundle/CallBundle/Entity/Call.php
index dab8a6510c9..a8854926c6e 100644
--- a/src/OroCRM/Bundle/CallBundle/Entity/Call.php
+++ b/src/OroCRM/Bundle/CallBundle/Entity/Call.php
@@ -6,6 +6,7 @@
use Doctrine\ORM\Mapping as ORM;
use Oro\Bundle\UserBundle\Entity\User;
use Oro\Bundle\EntityConfigBundle\Metadata\Annotation\Config;
+use Oro\Bundle\EntityConfigBundle\Metadata\Annotation\ConfigField;
use OroCRM\Bundle\ContactBundle\Entity\Contact;
use OroCRM\Bundle\AccountBundle\Entity\Account;
use OroCRM\Bundle\ContactBundle\Entity\ContactPhone;
@@ -18,6 +19,9 @@
* @Config(
* routeName="orocrm_call_index",
* defaultValues={
+ * "entity"={
+ * "icon"="icon-phone"
+ * },
* "ownership"={
* "owner_type"="USER",
* "owner_field_name"="owner",
@@ -59,6 +63,7 @@ class Call
* @var Account
* @ORM\ManyToOne(targetEntity="OroCRM\Bundle\AccountBundle\Entity\Account")
* @ORM\JoinColumn(name="related_account_id", referencedColumnName="id", onDelete="SET NULL", nullable=true)
+ * @ConfigField(defaultValues={"merge"={"relation_enable"=true, "relation_cast_method"="getSubject"}})
*/
protected $relatedAccount;
@@ -130,7 +135,7 @@ public function __construct()
/**
* Get id
*
- * @return integer
+ * @return integer
*/
public function getId()
{
@@ -146,14 +151,14 @@ public function getId()
public function setSubject($subject)
{
$this->subject = $subject;
-
+
return $this;
}
/**
* Get subject
*
- * @return string
+ * @return string
*/
public function getSubject()
{
@@ -169,14 +174,14 @@ public function getSubject()
public function setPhoneNumber($phoneNumber)
{
$this->phoneNumber = $phoneNumber;
-
+
return $this;
}
/**
* Get phoneNumber
*
- * @return string
+ * @return string
*/
public function getPhoneNumber()
{
@@ -192,14 +197,14 @@ public function getPhoneNumber()
public function setNotes($notes)
{
$this->notes = $notes;
-
+
return $this;
}
/**
* Get notes
*
- * @return string
+ * @return string
*/
public function getNotes()
{
@@ -215,14 +220,14 @@ public function getNotes()
public function setCallDateTime($callDateTime)
{
$this->callDateTime = $callDateTime;
-
+
return $this;
}
/**
* Get callDateTime
*
- * @return \DateTime
+ * @return \DateTime
*/
public function getCallDateTime()
{
@@ -238,14 +243,14 @@ public function getCallDateTime()
public function setDuration($duration)
{
$this->duration = $duration;
-
+
return $this;
}
/**
* Get duration
*
- * @return \DateTime
+ * @return \DateTime
*/
public function getDuration()
{
@@ -261,14 +266,14 @@ public function getDuration()
public function setDirection($direction)
{
$this->direction = $direction;
-
+
return $this;
}
/**
* Get direction
*
- * @return boolean
+ * @return boolean
*/
public function getDirection()
{
@@ -284,7 +289,7 @@ public function getDirection()
public function setOwner(User $owner = null)
{
$this->owner = $owner;
-
+
return $this;
}
@@ -307,7 +312,7 @@ public function getOwner()
public function setRelatedContact(Contact $relatedContact = null)
{
$this->relatedContact = $relatedContact;
-
+
return $this;
}
@@ -330,7 +335,7 @@ public function getRelatedContact()
public function setRelatedAccount(Account $relatedAccount = null)
{
$this->relatedAccount = $relatedAccount;
-
+
return $this;
}
@@ -353,7 +358,7 @@ public function getRelatedAccount()
public function setContactPhoneNumber(ContactPhone $contactPhoneNumber = null)
{
$this->contactPhoneNumber = $contactPhoneNumber;
-
+
return $this;
}
@@ -376,7 +381,7 @@ public function getContactPhoneNumber()
public function setCallStatus(CallStatus $callStatus = null)
{
$this->callStatus = $callStatus;
-
+
return $this;
}
diff --git a/src/OroCRM/Bundle/CallBundle/Resources/config/datagrid.yml b/src/OroCRM/Bundle/CallBundle/Resources/config/datagrid.yml
index 02bf95c2117..89be890e25e 100644
--- a/src/OroCRM/Bundle/CallBundle/Resources/config/datagrid.yml
+++ b/src/OroCRM/Bundle/CallBundle/Resources/config/datagrid.yml
@@ -88,6 +88,7 @@ datagrid:
rowAction: true
options:
entityHint: calls
+ export: true
widget-calls-grid:
source:
diff --git a/src/OroCRM/Bundle/CallBundle/Resources/config/navigation.yml b/src/OroCRM/Bundle/CallBundle/Resources/config/navigation.yml
index 81a6ecdc3c4..eb756b41af2 100644
--- a/src/OroCRM/Bundle/CallBundle/Resources/config/navigation.yml
+++ b/src/OroCRM/Bundle/CallBundle/Resources/config/navigation.yml
@@ -4,6 +4,7 @@ oro_menu_config:
label: orocrm.call.entity_plural_label
route: orocrm_call_index
extras:
+ position: 20
routes: ['orocrm_call_*']
description: List of calls
shortcut_call_list:
diff --git a/src/OroCRM/Bundle/CallBundle/Tests/Functional/API/RestCallsTest.php b/src/OroCRM/Bundle/CallBundle/Tests/Functional/API/RestCallsTest.php
index 5bb93955674..492503b948f 100644
--- a/src/OroCRM/Bundle/CallBundle/Tests/Functional/API/RestCallsTest.php
+++ b/src/OroCRM/Bundle/CallBundle/Tests/Functional/API/RestCallsTest.php
@@ -33,7 +33,11 @@ public function testCreate()
"callStatus" => 'completed'
)
);
- $this->client->request('POST', $this->client->generate('oro_api_post_call'), $request);
+ $this->client->request(
+ 'POST',
+ $this->client->generate('oro_api_post_call'),
+ $request
+ );
$result = $this->client->getResponse();
ToolsAPI::assertJsonResponse($result, 201);
@@ -51,7 +55,10 @@ public function testCreate()
*/
public function testGet($request)
{
- $this->client->request('GET', $this->client->generate('oro_api_get_calls'));
+ $this->client->request(
+ 'GET',
+ $this->client->generate('oro_api_get_calls')
+ );
$result = $this->client->getResponse();
$result = ToolsAPI::jsonToArray($result->getContent());
$id = $request['id'];
@@ -65,7 +72,10 @@ function ($a) use ($id) {
$this->assertNotEmpty($result);
$this->assertEquals($request['call']['subject'], reset($result)['subject']);
- $this->client->request('GET', $this->client->generate('oro_api_get_call', array('id' => $id)));
+ $this->client->request(
+ 'GET',
+ $this->client->generate('oro_api_get_call', array('id' => $id))
+ );
$result = $this->client->getResponse();
ToolsAPI::assertJsonResponse($result, 200);
$result = ToolsAPI::jsonToArray($result->getContent());
@@ -89,7 +99,10 @@ public function testUpdate($request)
ToolsAPI::assertJsonResponse($result, 204);
- $this->client->request('GET', $this->client->generate('oro_api_get_call', array('id' => $request['id'])));
+ $this->client->request(
+ 'GET',
+ $this->client->generate('oro_api_get_call', array('id' => $request['id']))
+ );
$result = $this->client->getResponse();
ToolsAPI::assertJsonResponse($result, 200);
@@ -112,7 +125,10 @@ public function testDelete($request)
);
$result = $this->client->getResponse();
ToolsAPI::assertJsonResponse($result, 204);
- $this->client->request('GET', $this->client->generate('oro_api_get_call', array('id' => $request['id'])));
+ $this->client->request(
+ 'GET',
+ $this->client->generate('oro_api_get_call', array('id' => $request['id']))
+ );
$result = $this->client->getResponse();
ToolsAPI::assertJsonResponse($result, 404);
}
diff --git a/src/OroCRM/Bundle/ContactBundle/Entity/Contact.php b/src/OroCRM/Bundle/ContactBundle/Entity/Contact.php
index 7f88e567d9a..015b4291c82 100644
--- a/src/OroCRM/Bundle/ContactBundle/Entity/Contact.php
+++ b/src/OroCRM/Bundle/ContactBundle/Entity/Contact.php
@@ -37,6 +37,9 @@
* routeName="orocrm_contact_index",
* routeView="orocrm_contact_view",
* defaultValues={
+ * "entity"={
+ * "icon"="icon-group"
+ * },
* "ownership"={
* "owner_type"="USER",
* "owner_field_name"="owner",
diff --git a/src/OroCRM/Bundle/ContactBundle/Entity/ContactAddress.php b/src/OroCRM/Bundle/ContactBundle/Entity/ContactAddress.php
index 65051e44aa7..e074ae8be36 100644
--- a/src/OroCRM/Bundle/ContactBundle/Entity/ContactAddress.php
+++ b/src/OroCRM/Bundle/ContactBundle/Entity/ContactAddress.php
@@ -13,7 +13,11 @@
/**
* @ORM\Table("orocrm_contact_address")
* @ORM\HasLifecycleCallbacks()
- * @Config()
+ * @Config(
+ * defaultValues={
+ * "entity"={"icon"="icon-map-marker"},
+ * }
+ * )
* @ORM\Entity
*/
class ContactAddress extends AbstractTypedAddress
diff --git a/src/OroCRM/Bundle/ContactBundle/Entity/ContactEmail.php b/src/OroCRM/Bundle/ContactBundle/Entity/ContactEmail.php
index 968baf91dbf..27a8bef2f80 100644
--- a/src/OroCRM/Bundle/ContactBundle/Entity/ContactEmail.php
+++ b/src/OroCRM/Bundle/ContactBundle/Entity/ContactEmail.php
@@ -14,7 +14,11 @@
* @ORM\Table("orocrm_contact_email", indexes={
* @ORM\Index(name="primary_email_idx", columns={"email", "is_primary"})
* })
- * @Config()
+ * @Config(
+ * defaultValues={
+ * "entity"={"icon"="icon-envelope"}
+ * }
+ * )
*/
class ContactEmail extends AbstractEmail implements EmailInterface
{
diff --git a/src/OroCRM/Bundle/ContactBundle/Entity/ContactPhone.php b/src/OroCRM/Bundle/ContactBundle/Entity/ContactPhone.php
index adab486f9c5..a3338f11cf8 100644
--- a/src/OroCRM/Bundle/ContactBundle/Entity/ContactPhone.php
+++ b/src/OroCRM/Bundle/ContactBundle/Entity/ContactPhone.php
@@ -14,7 +14,11 @@
* @ORM\Index(name="primary_phone_idx", columns={"phone", "is_primary"})
* })
* @ORM\Entity(repositoryClass="OroCRM\Bundle\ContactBundle\Entity\Repository\ContactPhoneRepository")
- * @Config()
+ * @Config(
+ * defaultValues={
+ * "entity"={"icon"="icon-phone"}
+ * }
+ * )
*/
class ContactPhone extends AbstractPhone
{
diff --git a/src/OroCRM/Bundle/ContactBundle/ImportExport/Converter/ContactDataConverter.php b/src/OroCRM/Bundle/ContactBundle/ImportExport/Converter/ContactDataConverter.php
index d8c26bb29a1..ffaa20c657e 100644
--- a/src/OroCRM/Bundle/ContactBundle/ImportExport/Converter/ContactDataConverter.php
+++ b/src/OroCRM/Bundle/ContactBundle/ImportExport/Converter/ContactDataConverter.php
@@ -23,6 +23,7 @@ class ContactDataConverter extends AbstractTableDataConverter implements QueryBu
'ID' => 'id',
'Name Prefix' => 'namePrefix',
'First Name' => 'firstName',
+ 'Middle Name' => 'middleName',
'Last Name' => 'lastName',
'Name Suffix' => 'nameSuffix',
'Gender' => 'gender',
diff --git a/src/OroCRM/Bundle/ContactBundle/ImportExport/Serializer/Normalizer/ContactNormalizer.php b/src/OroCRM/Bundle/ContactBundle/ImportExport/Serializer/Normalizer/ContactNormalizer.php
index 2a3d0a8247a..124bb4dd077 100644
--- a/src/OroCRM/Bundle/ContactBundle/ImportExport/Serializer/Normalizer/ContactNormalizer.php
+++ b/src/OroCRM/Bundle/ContactBundle/ImportExport/Serializer/Normalizer/ContactNormalizer.php
@@ -31,6 +31,7 @@ class ContactNormalizer implements NormalizerInterface, DenormalizerInterface, S
'id',
'namePrefix',
'firstName',
+ 'middleName',
'lastName',
'nameSuffix',
'gender',
diff --git a/src/OroCRM/Bundle/ContactBundle/Resources/config/datagrid.yml b/src/OroCRM/Bundle/ContactBundle/Resources/config/datagrid.yml
index b5bf845df2d..1367682e6f3 100644
--- a/src/OroCRM/Bundle/ContactBundle/Resources/config/datagrid.yml
+++ b/src/OroCRM/Bundle/ContactBundle/Resources/config/datagrid.yml
@@ -1,7 +1,5 @@
datagrid:
dashboard-my-contacts-activity-grid:
- options:
- entityHint: contact
source:
type: orm
acl_resource: orocrm_call_view
@@ -41,6 +39,7 @@ datagrid:
primaryPhone:
label: orocrm.contact.contactphone.phone.label
options:
+ entityHint: contact
toolbarOptions:
hide: true
pageSize:
@@ -96,6 +95,7 @@ datagrid:
link: delete_link
options:
entityHint: group
+
# contacts assigned to group, shown on orocrm_contact_group_update route
contact-group-contacts-grid:
source:
@@ -158,6 +158,7 @@ datagrid:
selectors:
included: '#groupAppendContacts'
excluded: '#groupRemoveContacts'
+
# contacts main grid show on orocrm_contact_index route
contacts-grid:
extended_entity_name: %orocrm_contact.entity.class%
@@ -340,6 +341,7 @@ datagrid:
icon: trash
options:
entityHint: contact
+ export: true
# contact email datagrid
contacts-email-grid:
diff --git a/src/OroCRM/Bundle/ContactBundle/Resources/config/navigation.yml b/src/OroCRM/Bundle/ContactBundle/Resources/config/navigation.yml
index 07922fef7b5..ef24b73a192 100644
--- a/src/OroCRM/Bundle/ContactBundle/Resources/config/navigation.yml
+++ b/src/OroCRM/Bundle/ContactBundle/Resources/config/navigation.yml
@@ -10,12 +10,14 @@ oro_menu_config:
label: orocrm.contact.entity_plural_label
route: orocrm_contact_index
extras:
+ position: 10
routes: ['/^orocrm_contact_(?!group\w+|group\w+)\w+$/']
description: List of contacts
contact_group_list:
label: orocrm.contact.group.entity_plural_label
route: orocrm_contact_group_index
extras:
+ position: 45
routes: ['orocrm_contact_group_*']
description: List of contact groups
diff --git a/src/OroCRM/Bundle/ContactBundle/Resources/config/search.yml b/src/OroCRM/Bundle/ContactBundle/Resources/config/search.yml
index 096dc2eaf15..e6794b33b9a 100644
--- a/src/OroCRM/Bundle/ContactBundle/Resources/config/search.yml
+++ b/src/OroCRM/Bundle/ContactBundle/Resources/config/search.yml
@@ -6,7 +6,6 @@ OroCRM\Bundle\ContactBundle\Entity\Contact:
parameters:
id: id
search_template: OroCRMContactBundle:Contact:searchResult.html.twig
- entity_icon_class: icon-envelope
fields:
-
name: namePrefix
diff --git a/src/OroCRM/Bundle/ContactBundle/Resources/public/import/contacts_sample.csv b/src/OroCRM/Bundle/ContactBundle/Resources/public/import/contacts_sample.csv
index f7e5dcf4a9d..79717052495 100644
--- a/src/OroCRM/Bundle/ContactBundle/Resources/public/import/contacts_sample.csv
+++ b/src/OroCRM/Bundle/ContactBundle/Resources/public/import/contacts_sample.csv
@@ -1,3 +1,3 @@
-"ID","Name Prefix","First Name","Last Name","Name Suffix","Gender","Description","Job Title","Fax","Skype","Twitter","Facebook","GooglePlus","LinkedIn","Birthday","Source","Method","Owner Username","Owner","Assigned To Username","Assigned To","Primary Email","Email 1","Email 2","Primary Phone","Phone 1","Phone 2","Group 1","Group 2","Account 1","Account 2","Primary Address Label","Primary Address First Name","Primary Address Last Name","Primary Address Street","Primary Address Street2","Primary Address City","Primary Address Postal Code","Primary Address Region Text","Primary Address Region","Primary Address Country","Address 1 Label","Address 1 First Name","Address 1 Last Name","Address 1 Street","Address 1 Street2","Address 1 City","Address 1 Postal Code","Address 1 Region Text","Address 1 Region","Address 1 Country","Address 2 Label","Address 2 First Name","Address 2 Last Name","Address 2 Street","Address 2 Street2","Address 2 City","Address 2 Postal Code","Address 2 Region Text","Address 2 Region","Address 2 Country"
-1,"Mr.","Jerry","Coleman","Jr.","male","Sample Contact","Manager","713-450-0721","crm-jerrycoleman","crm-jerrycoleman","crm-jerrycoleman","https://plus.google.com/454646545646546","http://www.linkedin.com/in/crm-jerrycoleman",1973-03-07,"website","phone","bettina.bad","Bettina Bad","bettina.bad","Bettina Bad","JerryAColeman@armyspy.com","JerryAColeman@cuvox.de","JerryAColeman@teleworm.us","585-255-1127","914-412-0298","310-430-7875","Marketing Group","Sales Group","Welsight73A_Coleman","DistaildD_Coleman",,"Jerry","Coleman","1215 Caldwell Road",,"Rochester",14608,,"NY","US",,"Jerry","Coleman","4677 Pallet Street",,"New York",10011,,"NY","US",,"Jerry","Coleman","52 Jarvisville Road",,"Westbury",11590,,"NY","US"
-,,"Debra","Bailey",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
+"ID","Name Prefix","First Name","Middle Name","Last Name","Name Suffix","Gender","Description","Job Title","Fax","Skype","Twitter","Facebook","GooglePlus","LinkedIn","Birthday","Source","Method","Owner Username","Owner","Assigned To Username","Assigned To","Primary Email","Email 1","Email 2","Primary Phone","Phone 1","Phone 2","Group 1","Group 2","Account 1","Account 2","Primary Address Label","Primary Address First Name","Primary Address Last Name","Primary Address Street","Primary Address Street2","Primary Address City","Primary Address Postal Code","Primary Address Region Text","Primary Address Region","Primary Address Country","Address 1 Label","Address 1 First Name","Address 1 Last Name","Address 1 Street","Address 1 Street2","Address 1 City","Address 1 Postal Code","Address 1 Region Text","Address 1 Region","Address 1 Country","Address 2 Label","Address 2 First Name","Address 2 Last Name","Address 2 Street","Address 2 Street2","Address 2 City","Address 2 Postal Code","Address 2 Region Text","Address 2 Region","Address 2 Country"
+1,"Mr.","Jerry",,"Coleman","Jr.","male","Sample Contact","Manager","713-450-0721","crm-jerrycoleman","crm-jerrycoleman","crm-jerrycoleman","https://plus.google.com/454646545646546","http://www.linkedin.com/in/crm-jerrycoleman",1973-03-07,"website","phone","bettina.bad","Bettina Bad","bettina.bad","Bettina Bad","JerryAColeman@armyspy.com","JerryAColeman@cuvox.de","JerryAColeman@teleworm.us","585-255-1127","914-412-0298","310-430-7875","Marketing Group","Sales Group","Welsight73A_Coleman","DistaildD_Coleman",,"Jerry","Coleman","1215 Caldwell Road",,"Rochester",14608,,"NY","US",,"Jerry","Coleman","4677 Pallet Street",,"New York",10011,,"NY","US",,"Jerry","Coleman","52 Jarvisville Road",,"Westbury",11590,,"NY","US"
+,,"Debra",,"Bailey",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
diff --git a/src/OroCRM/Bundle/ContactBundle/Tests/Functional/API/RestContactApiTest.php b/src/OroCRM/Bundle/ContactBundle/Tests/Functional/API/RestContactApiTest.php
index 4d3607f6ef3..e14009bee4d 100755
--- a/src/OroCRM/Bundle/ContactBundle/Tests/Functional/API/RestContactApiTest.php
+++ b/src/OroCRM/Bundle/ContactBundle/Tests/Functional/API/RestContactApiTest.php
@@ -132,7 +132,11 @@ public function testCreateContact()
'assignedTo' => $user ? $user->getId() : null,
)
);
- $this->client->request('POST', $this->client->generate('oro_api_post_contact'), $request);
+ $this->client->request(
+ 'POST',
+ $this->client->generate('oro_api_post_contact'),
+ $request
+ );
$result = $this->client->getResponse();
ToolsAPI::assertJsonResponse($result, 201);
@@ -150,7 +154,10 @@ public function testCreateContact()
*/
public function testGetContact($request)
{
- $this->client->request('GET', $this->client->generate('oro_api_get_contacts'));
+ $this->client->request(
+ 'GET',
+ $this->client->generate('oro_api_get_contacts')
+ );
$result = $this->client->getResponse();
$entities = ToolsAPI::jsonToArray($result->getContent());
$this->assertNotEmpty($entities);
@@ -223,7 +230,10 @@ public function testUpdateContact($contact, $request)
$result = $this->client->getResponse();
ToolsAPI::assertJsonResponse($result, 204);
- $this->client->request('GET', $this->client->generate('oro_api_get_contact', array('id' => $contact['id'])));
+ $this->client->request(
+ 'GET',
+ $this->client->generate('oro_api_get_contact', array('id' => $contact['id']))
+ );
$result = $this->client->getResponse();
ToolsAPI::assertJsonResponse($result, 200);
@@ -253,7 +263,10 @@ public function testDeleteContact($contact)
$result = $this->client->getResponse();
ToolsAPI::assertJsonResponse($result, 204);
- $this->client->request('GET', $this->client->generate('oro_api_get_contact', array('id' => $contact['id'])));
+ $this->client->request(
+ 'GET',
+ $this->client->generate('oro_api_get_contact', array('id' => $contact['id']))
+ );
$result = $this->client->getResponse();
ToolsAPI::assertJsonResponse($result, 404);
}
diff --git a/src/OroCRM/Bundle/ContactBundle/Tests/Functional/API/RestContactGroupsApiTest.php b/src/OroCRM/Bundle/ContactBundle/Tests/Functional/API/RestContactGroupsApiTest.php
index 5d48898e53c..85bff58efa8 100755
--- a/src/OroCRM/Bundle/ContactBundle/Tests/Functional/API/RestContactGroupsApiTest.php
+++ b/src/OroCRM/Bundle/ContactBundle/Tests/Functional/API/RestContactGroupsApiTest.php
@@ -40,15 +40,19 @@ public function testCreateContactGroup()
/**
* @param $request
+ *
* @return array
* @depends testCreateContactGroup
*/
public function testGetContactGroup($request)
{
- $this->client->request('GET', $this->client->generate('oro_api_get_contactgroups'));
+ $this->client->request(
+ 'GET',
+ $this->client->generate('oro_api_get_contactgroups')
+ );
$result = $this->client->getResponse();
$result = json_decode($result->getContent(), true);
- $flag = 1;
+ $flag = 1;
foreach ($result as $group) {
if ($group['label'] == $request['contact_group']['label']) {
$flag = 0;
@@ -57,7 +61,10 @@ public function testGetContactGroup($request)
}
$this->assertEquals(0, $flag);
- $this->client->request('GET', $this->client->generate('oro_api_get_contactgroup', array('id' => $group['id'])));
+ $this->client->request(
+ 'GET',
+ $this->client->generate('oro_api_get_contactgroup', array('id' => $group['id']))
+ );
$result = $this->client->getResponse();
ToolsAPI::assertJsonResponse($result, 200);
@@ -67,6 +74,7 @@ public function testGetContactGroup($request)
/**
* @param $group
* @param $request
+ *
* @depends testGetContactGroup
* @depends testCreateContactGroup
*/
@@ -80,7 +88,11 @@ public function testUpdateContactGroup($group, $request)
);
$result = $this->client->getResponse();
ToolsAPI::assertJsonResponse($result, 204);
- $this->client->request('GET', $this->client->generate('oro_api_get_contactgroup', array('id' => $group['id'])));
+
+ $this->client->request(
+ 'GET',
+ $this->client->generate('oro_api_get_contactgroup', array('id' => $group['id']))
+ );
$result = $this->client->getResponse();
ToolsAPI::assertJsonResponse($result, 200);
$result = json_decode($result->getContent(), true);
@@ -89,6 +101,7 @@ public function testUpdateContactGroup($group, $request)
/**
* @param $group
+ *
* @depends testGetContactGroup
*/
public function testDeleteContact($group)
@@ -99,7 +112,11 @@ public function testDeleteContact($group)
);
$result = $this->client->getResponse();
ToolsAPI::assertJsonResponse($result, 204);
- $this->client->request('GET', $this->client->generate('oro_api_get_contactgroup', array('id' => $group['id'])));
+
+ $this->client->request(
+ 'GET',
+ $this->client->generate('oro_api_get_contactgroup', array('id' => $group['id']))
+ );
$result = $this->client->getResponse();
ToolsAPI::assertJsonResponse($result, 404);
}
diff --git a/src/OroCRM/Bundle/ContactBundle/Tests/Functional/API/SoapContactApiTest.php b/src/OroCRM/Bundle/ContactBundle/Tests/Functional/API/SoapContactApiTest.php
index e44137097cc..ff0eb9bfbe3 100755
--- a/src/OroCRM/Bundle/ContactBundle/Tests/Functional/API/SoapContactApiTest.php
+++ b/src/OroCRM/Bundle/ContactBundle/Tests/Functional/API/SoapContactApiTest.php
@@ -46,8 +46,6 @@ public static function tearDownAfterClass()
*/
public function testCreateContact($request)
{
- //$this->markTestIncomplete('Should be fixed in scope of BAP-1383');
-
$result = $this->client->getSoap()->createContact($request);
$this->assertInternalType('int', $result);
$this->assertGreaterThan(0, $result, $this->client->getSoap()->__getLastResponse());
@@ -117,7 +115,6 @@ public function testUpdateContact($request)
* @param $request
* @dataProvider requestsApi
* @depends testCreateContact
- * @throws \Exception|\SoapFault
*/
public function testDeleteContact($request)
{
@@ -127,12 +124,8 @@ public function testDeleteContact($request)
$this->assertTrue($result);
$this->setExpectedException('\SoapFault', 'Record with ID "' . $contactId . '" can not be found');
- try {
- $this->client->getSoap()->getContact($contactId);
- } catch (\SoapFault $e) {
- $this->assertEquals('NOT_FOUND', $e->faultcode);
- throw $e;
- }
+
+ $this->client->getSoap()->getContact($contactId);
}
/**
diff --git a/src/OroCRM/Bundle/ContactBundle/Tests/Functional/API/SoapContactGroupApiTest.php b/src/OroCRM/Bundle/ContactBundle/Tests/Functional/API/SoapContactGroupApiTest.php
index ccff29f813e..b7b09b7bf4c 100755
--- a/src/OroCRM/Bundle/ContactBundle/Tests/Functional/API/SoapContactGroupApiTest.php
+++ b/src/OroCRM/Bundle/ContactBundle/Tests/Functional/API/SoapContactGroupApiTest.php
@@ -76,6 +76,7 @@ public function testUpdateContact($request, $group)
$request['label'] .= '_Updated';
$result = $this->client->getSoap()->updateContactGroup($group['id'], $request);
$this->assertTrue($result);
+
$group = $this->client->getSoap()->getContactGroup($group['id']);
$group = ToolsAPI::classToArray($group);
$this->assertEquals($request['label'], $group['label']);
@@ -90,12 +91,9 @@ public function testDeleteContactGroup($group)
{
$result = $this->client->getSoap()->deleteContactGroup($group['id']);
$this->assertTrue($result);
- try {
- $this->client->getSoap()->getContactGroup($group['id']);
- } catch (\SoapFault $e) {
- if ($e->faultcode != 'NOT_FOUND') {
- throw $e;
- }
- }
+
+ $this->setExpectedException('\SoapFault', 'Record with ID "' . $group['id'] . '" can not be found');
+
+ $this->client->getSoap()->getContactGroup($group['id']);
}
}
diff --git a/src/OroCRM/Bundle/ContactBundle/Tests/Unit/ImportExport/Converter/ContactDataConverterTest.php b/src/OroCRM/Bundle/ContactBundle/Tests/Unit/ImportExport/Converter/ContactDataConverterTest.php
index c8db58a4ec7..596cd2a2380 100644
--- a/src/OroCRM/Bundle/ContactBundle/Tests/Unit/ImportExport/Converter/ContactDataConverterTest.php
+++ b/src/OroCRM/Bundle/ContactBundle/Tests/Unit/ImportExport/Converter/ContactDataConverterTest.php
@@ -23,6 +23,7 @@ class ContactDataConverterTest extends \PHPUnit_Framework_TestCase
'id',
'namePrefix',
'firstName',
+ 'middleName',
'lastName',
'nameSuffix',
'gender',
@@ -120,6 +121,7 @@ public function convertToExportFormatDataProvider()
'ID' => '',
'Name Prefix' => '',
'First Name' => 'John',
+ 'Middle Name' => '',
'Last Name' => 'Doe',
'Name Suffix' => '',
'Gender' => '',
@@ -177,6 +179,7 @@ public function convertToExportFormatDataProvider()
'id' => 69,
'namePrefix' => 'Mr.',
'firstName' => 'John',
+ 'middleName' => 'Middle',
'lastName' => 'Doe',
'nameSuffix' => 'Jr.',
'gender' => 'male',
@@ -248,6 +251,7 @@ public function convertToExportFormatDataProvider()
'ID' => '69',
'Name Prefix' => 'Mr.',
'First Name' => 'John',
+ 'Middle Name' => 'Middle',
'Last Name' => 'Doe',
'Name Suffix' => 'Jr.',
'Gender' => 'male',
diff --git a/src/OroCRM/Bundle/ContactBundle/Tests/Unit/ImportExport/Serializer/Normalizer/ContactNormalizerTest.php b/src/OroCRM/Bundle/ContactBundle/Tests/Unit/ImportExport/Serializer/Normalizer/ContactNormalizerTest.php
index 4ae4b9ad9b2..54cdea1cfbe 100644
--- a/src/OroCRM/Bundle/ContactBundle/Tests/Unit/ImportExport/Serializer/Normalizer/ContactNormalizerTest.php
+++ b/src/OroCRM/Bundle/ContactBundle/Tests/Unit/ImportExport/Serializer/Normalizer/ContactNormalizerTest.php
@@ -109,6 +109,7 @@ public function normalizeScalarFieldsDataProvider()
->setId(1)
->setNamePrefix('name_prefix')
->setFirstName('first_name')
+ ->setMiddleName('middle_name')
->setLastName('last_name')
->setNameSuffix('name_suffix')
->setGender('male')
@@ -121,6 +122,7 @@ public function normalizeScalarFieldsDataProvider()
'id' => 1,
'namePrefix' => 'name_prefix',
'firstName' => 'first_name',
+ 'middleName' => 'middle_name',
'lastName' => 'last_name',
'nameSuffix' => 'name_suffix',
'gender' => 'male',
@@ -150,6 +152,7 @@ public function normalizeScalarFieldsDataProvider()
'id' => null,
'namePrefix' => null,
'firstName' => null,
+ 'middleName' => null,
'lastName' => null,
'nameSuffix' => null,
'gender' => null,
diff --git a/src/OroCRM/Bundle/ContactUsBundle/Controller/ContactRequestController.php b/src/OroCRM/Bundle/ContactUsBundle/Controller/ContactRequestController.php
new file mode 100644
index 00000000000..8cee25fe28e
--- /dev/null
+++ b/src/OroCRM/Bundle/ContactUsBundle/Controller/ContactRequestController.php
@@ -0,0 +1,144 @@
+ $contactRequest
+ ];
+ }
+
+ /**
+ * @Route(name="orocrm_contactus_request_index")
+ * @Template
+ * @AclAncestor("orocrm_contactus_request_view")
+ */
+ public function indexAction()
+ {
+ return [];
+ }
+
+ /**
+ * @Route("/info/{id}", name="orocrm_contactus_request_info", requirements={"id"="\d+"})
+ * @Template
+ * @AclAncestor("orocrm_contactus_request_view")
+ */
+ public function infoAction(ContactRequest $contactRequest)
+ {
+ return [
+ 'entity' => $contactRequest
+ ];
+ }
+
+ /**
+ * @Route("/update/{id}", name="orocrm_contactus_request_update", requirements={"id"="\d+"})
+ * @Template
+ * @Acl(
+ * id="orocrm_contactus_request_edit",
+ * type="entity",
+ * permission="EDIT",
+ * class="OroCRMContactUsBundle:ContactRequest"
+ * )
+ */
+ public function updateAction(ContactRequest $contactRequest)
+ {
+ return $this->update($contactRequest);
+ }
+
+ /**
+ * @Route("/create", name="orocrm_contactus_request_create")
+ * @Template("OroCRMContactUsBundle:ContactRequest:update.html.twig")
+ * @Acl(
+ * id="orocrm_contactus_request_create",
+ * type="entity",
+ * permission="CREATE",
+ * class="OroCRMContactUsBundle:ContactRequest"
+ * )
+ */
+ public function createAction()
+ {
+ return $this->update(new ContactRequest());
+ }
+
+ /**
+ * @Route("/delete/{id}", name="orocrm_contactus_request_delete", requirements={"id"="\d+"})
+ * @Acl(
+ * id="orocrm_contactus_request_delete",
+ * type="entity",
+ * permission="DELETE",
+ * class="OroCRMContactUsBundle:ContactRequest"
+ * )
+ */
+ public function deleteAction(ContactRequest $contactRequest)
+ {
+ /** @var EntityManager $em */
+ $em = $this->get('doctrine.orm.entity_manager');
+
+ $em->remove($contactRequest);
+ $em->flush();
+
+ return new JsonResponse('', Codes::HTTP_OK);
+ }
+
+ /**
+ * @param ContactRequest $contactRequest
+ *
+ * @return array|\Symfony\Component\HttpFoundation\RedirectResponse
+ */
+ protected function update(ContactRequest $contactRequest)
+ {
+ $handler = $this->get('orocrm_contact_us.contact_request.form.handler');
+
+ if ($handler->process($contactRequest)) {
+ $this->get('session')->getFlashBag()->add(
+ 'success',
+ $this->get('translator')->trans('orocrm.contactus.contactrequest.entity.saved')
+ );
+
+ return $this->get('oro_ui.router')->redirectAfterSave(
+ [
+ 'route' => 'orocrm_contactus_request_update',
+ 'parameters' => ['id' => $contactRequest->getId()]
+ ],
+ [
+ 'route' => 'orocrm_contactus_request_view',
+ 'parameters' => ['id' => $contactRequest->getId()]
+ ],
+ $contactRequest
+ );
+ }
+
+ return [
+ 'entity' => $contactRequest,
+ 'form' => $handler->getForm()->createView()
+ ];
+ }
+}
diff --git a/src/OroCRM/Bundle/ContactUsBundle/DependencyInjection/OroCRMContactUsExtension.php b/src/OroCRM/Bundle/ContactUsBundle/DependencyInjection/OroCRMContactUsExtension.php
new file mode 100644
index 00000000000..c737f5a8e6c
--- /dev/null
+++ b/src/OroCRM/Bundle/ContactUsBundle/DependencyInjection/OroCRMContactUsExtension.php
@@ -0,0 +1,20 @@
+load('services.yml');
+ }
+}
diff --git a/src/OroCRM/Bundle/ContactUsBundle/Entity/AbstractContactRequest.php b/src/OroCRM/Bundle/ContactUsBundle/Entity/AbstractContactRequest.php
new file mode 100644
index 00000000000..80bcfa9688b
--- /dev/null
+++ b/src/OroCRM/Bundle/ContactUsBundle/Entity/AbstractContactRequest.php
@@ -0,0 +1,212 @@
+id;
+ }
+
+ /**
+ * @param string $firstName
+ */
+ public function setFirstName($firstName)
+ {
+ $this->firstName = $firstName;
+ }
+
+ /**
+ * @return string
+ */
+ public function getFirstName()
+ {
+ return $this->firstName;
+ }
+
+ /**
+ * @param string $lastName
+ */
+ public function setLastName($lastName)
+ {
+ $this->lastName = $lastName;
+ }
+
+ /**
+ * @return string
+ */
+ public function getLastName()
+ {
+ return $this->lastName;
+ }
+
+ /**
+ * @param string $emailAddress
+ */
+ public function setEmailAddress($emailAddress)
+ {
+ $this->emailAddress = $emailAddress;
+ }
+
+ /**
+ * @return string
+ */
+ public function getEmailAddress()
+ {
+ return $this->emailAddress;
+ }
+
+ /**
+ * @param string $phone
+ */
+ public function setPhone($phone)
+ {
+ $this->phone = $phone;
+ }
+
+ /**
+ * @return string
+ */
+ public function getPhone()
+ {
+ return $this->phone;
+ }
+
+ /**
+ * @param string $comment
+ */
+ public function setComment($comment)
+ {
+ $this->comment = $comment;
+ }
+
+ /**
+ * @return string
+ */
+ public function getComment()
+ {
+ return $this->comment;
+ }
+
+ /**
+ * @param \DateTime $createdAt
+ */
+ public function setCreatedAt(\DateTime $createdAt)
+ {
+ $this->createdAt = $createdAt;
+ }
+
+ /**
+ * @return \DateTime
+ */
+ public function getCreatedAt()
+ {
+ return $this->createdAt;
+ }
+
+ /**
+ * @param \DateTime $updatedAt
+ */
+ public function setUpdatedAt(\DateTime $updatedAt)
+ {
+ $this->updatedAt = $updatedAt;
+ }
+
+ /**
+ * @return \DateTime
+ */
+ public function getUpdatedAt()
+ {
+ return $this->updatedAt;
+ }
+
+ /**
+ * @ORM\PreUpdate()
+ */
+ public function preUpdate()
+ {
+ $this->updatedAt = new \DateTime('now', new \DateTimeZone('UTC'));
+ }
+
+ /**
+ * @ORM\PrePersist()
+ */
+ public function prePersist()
+ {
+ $this->createdAt = $this->updatedAt = new \DateTime('now', new \DateTimeZone('UTC'));
+ }
+}
diff --git a/src/OroCRM/Bundle/ContactUsBundle/Entity/ContactReason.php b/src/OroCRM/Bundle/ContactUsBundle/Entity/ContactReason.php
new file mode 100644
index 00000000000..1e86018b312
--- /dev/null
+++ b/src/OroCRM/Bundle/ContactUsBundle/Entity/ContactReason.php
@@ -0,0 +1,68 @@
+label = $label;
+ }
+
+ /**
+ * @return int
+ */
+ public function getId()
+ {
+ return $this->id;
+ }
+
+ /**
+ * @param string $label
+ */
+ public function setLabel($label)
+ {
+ $this->label = $label;
+ }
+
+ /**
+ * @return string
+ */
+ public function getLabel()
+ {
+ return $this->label;
+ }
+
+ /**
+ * @return string
+ */
+ public function __toString()
+ {
+ return $this->getLabel();
+ }
+}
diff --git a/src/OroCRM/Bundle/ContactUsBundle/Entity/ContactRequest.php b/src/OroCRM/Bundle/ContactUsBundle/Entity/ContactRequest.php
new file mode 100644
index 00000000000..d631bb074ee
--- /dev/null
+++ b/src/OroCRM/Bundle/ContactUsBundle/Entity/ContactRequest.php
@@ -0,0 +1,334 @@
+calls = new ArrayCollection();
+ $this->emails = new ArrayCollection();
+ }
+
+ /**
+ * @param string $organizationName
+ */
+ public function setOrganizationName($organizationName)
+ {
+ $this->organizationName = $organizationName;
+ }
+
+ /**
+ * @return string
+ */
+ public function getOrganizationName()
+ {
+ return $this->organizationName;
+ }
+
+ /**
+ * @param string $preferredContactMethod
+ */
+ public function setPreferredContactMethod($preferredContactMethod)
+ {
+ $this->preferredContactMethod = $preferredContactMethod;
+ }
+
+ /**
+ * @return string
+ */
+ public function getPreferredContactMethod()
+ {
+ return $this->preferredContactMethod;
+ }
+
+ /**
+ * @param ContactReason $contactReason
+ */
+ public function setContactReason(ContactReason $contactReason = null)
+ {
+ $this->contactReason = $contactReason;
+ }
+
+ /**
+ * @return ContactReason
+ */
+ public function getContactReason()
+ {
+ return $this->contactReason;
+ }
+
+ /**
+ * @param string $feedback
+ */
+ public function setFeedback($feedback)
+ {
+ $this->feedback = $feedback;
+ }
+
+ /**
+ * @return string
+ */
+ public function getFeedback()
+ {
+ return $this->feedback;
+ }
+
+ /**
+ * @param Lead $lead
+ */
+ public function setLead(Lead $lead)
+ {
+ $this->lead = $lead;
+ }
+
+ /**
+ * @return Lead
+ */
+ public function getLead()
+ {
+ return $this->lead;
+ }
+
+ /**
+ * @param Opportunity $opportunity
+ */
+ public function setOpportunity(Opportunity $opportunity)
+ {
+ $this->opportunity = $opportunity;
+ }
+
+ /**
+ * @return Opportunity
+ */
+ public function getOpportunity()
+ {
+ return $this->opportunity;
+ }
+
+ /**
+ * @return ArrayCollection
+ */
+ public function getCalls()
+ {
+ return $this->calls;
+ }
+
+ /**
+ * @param Call $call
+ */
+ public function addCall(Call $call)
+ {
+ if (!$this->hasCall($call)) {
+ $this->getCalls()->add($call);
+ }
+ }
+
+ /**
+ * @param Call $call
+ */
+ public function removeCall(Call $call)
+ {
+ if ($this->hasCall($call)) {
+ $this->getCalls()->removeElement($call);
+ }
+ }
+
+ /**
+ * @param Call $call
+ *
+ * @return bool
+ */
+ public function hasCall(Call $call)
+ {
+ return $this->getCalls()->contains($call);
+ }
+
+ /**
+ * @return ArrayCollection
+ */
+ public function getEmails()
+ {
+ return $this->emails;
+ }
+
+ /**
+ * @param Email $email
+ */
+ public function addEmail(Email $email)
+ {
+ if (!$this->hasEmail($email)) {
+ $this->getEmails()->add($email);
+ }
+ }
+
+ /**
+ * @param Email $email
+ */
+ public function removeEmail(Email $email)
+ {
+ if ($this->hasEmail($email)) {
+ $this->getEmails()->removeElement($email);
+ }
+ }
+
+ /**
+ * @param Email $email
+ *
+ * @return bool
+ */
+ public function hasEmail(Email $email)
+ {
+ return $this->getEmails()->contains($email);
+ }
+
+ /**
+ * @param WorkflowItem $workflowItem
+ */
+ public function setWorkflowItem(WorkflowItem $workflowItem)
+ {
+ $this->workflowItem = $workflowItem;
+ }
+
+ /**
+ * @return WorkflowItem
+ */
+ public function getWorkflowItem()
+ {
+ return $this->workflowItem;
+ }
+
+ /**
+ * @param WorkflowStep $workflowStep
+ */
+ public function setWorkflowStep(WorkflowStep $workflowStep)
+ {
+ $this->workflowStep = $workflowStep;
+ }
+
+ /**
+ * @return WorkflowStep
+ */
+ public function getWorkflowStep()
+ {
+ return $this->workflowStep;
+ }
+}
diff --git a/src/OroCRM/Bundle/ContactUsBundle/Form/Handler/ContactRequestHandler.php b/src/OroCRM/Bundle/ContactUsBundle/Form/Handler/ContactRequestHandler.php
new file mode 100644
index 00000000000..969a018d51d
--- /dev/null
+++ b/src/OroCRM/Bundle/ContactUsBundle/Form/Handler/ContactRequestHandler.php
@@ -0,0 +1,67 @@
+form = $form;
+ $this->request = $request;
+ $this->em = $em;
+ }
+
+ /**
+ * Process form
+ *
+ * @param ContactRequest $entity
+ *
+ * @return bool True on successful processing, false otherwise
+ */
+ public function process(ContactRequest $entity)
+ {
+ $this->getForm()->setData($entity);
+
+ if (in_array($this->request->getMethod(), array('POST', 'PUT'))) {
+ $this->getForm()->submit($this->request);
+
+ if ($this->getForm()->isValid()) {
+ $this->em->persist($entity);
+ $this->em->flush();
+
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * @return FormInterface
+ */
+ public function getForm()
+ {
+ return $this->form;
+ }
+}
diff --git a/src/OroCRM/Bundle/ContactUsBundle/Form/Type/ContactRequestType.php b/src/OroCRM/Bundle/ContactUsBundle/Form/Type/ContactRequestType.php
new file mode 100644
index 00000000000..3f61ceac0c3
--- /dev/null
+++ b/src/OroCRM/Bundle/ContactUsBundle/Form/Type/ContactRequestType.php
@@ -0,0 +1,183 @@
+add(
+ 'firstName',
+ 'text',
+ ['required' => true, 'label' => 'orocrm.contactus.contactrequest.first_name.label']
+ );
+ $builder->add(
+ 'lastName',
+ 'text',
+ ['required' => true, 'label' => 'orocrm.contactus.contactrequest.last_name.label']
+ );
+ $builder->add(
+ 'emailAddress',
+ 'text',
+ ['required' => true, 'label' => 'orocrm.contactus.contactrequest.email_address.label']
+ );
+ $builder->add('phone', 'text', ['required' => false, 'label' => 'orocrm.contactus.contactrequest.phone.label']);
+ $builder->add('comment', 'textarea', ['label' => 'orocrm.contactus.contactrequest.comment.label']);
+ $builder->add('submit', 'submit');
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function setDefaultOptions(OptionsResolverInterface $resolver)
+ {
+ $resolver->setDefaults(
+ [
+ 'data_class' => 'OroCRM\Bundle\ContactUsBundle\Entity\ContactRequest',
+ ]
+ );
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getParent()
+ {
+ return 'oro_channel_aware_form';
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getDefaultCss()
+ {
+ return <<Form has been submitted successfully
{back_link}';
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function geFormLayout()
+ {
+ return 'OroCRMContactUsBundle::form.html.twig';
+ }
+}
diff --git a/src/OroCRM/Bundle/ContactUsBundle/Migrations/DataFixtures/ORM/v1_0/LoadContactReasonData.php b/src/OroCRM/Bundle/ContactUsBundle/Migrations/DataFixtures/ORM/v1_0/LoadContactReasonData.php
new file mode 100644
index 00000000000..d8238765650
--- /dev/null
+++ b/src/OroCRM/Bundle/ContactUsBundle/Migrations/DataFixtures/ORM/v1_0/LoadContactReasonData.php
@@ -0,0 +1,32 @@
+persist($method);
+ }
+
+ $manager->flush();
+ }
+}
diff --git a/src/OroCRM/Bundle/ContactUsBundle/OroCRMContactUsBundle.php b/src/OroCRM/Bundle/ContactUsBundle/OroCRMContactUsBundle.php
new file mode 100644
index 00000000000..d2cb39f358d
--- /dev/null
+++ b/src/OroCRM/Bundle/ContactUsBundle/OroCRMContactUsBundle.php
@@ -0,0 +1,9 @@
+
+ {{ UI.addButton({
+ 'path' : path('orocrm_contactus_request_create'),
+ 'entity_label': 'orocrm.contactus.contactrequest.entity_label'|trans,
+ }) }}
+
+ {% endif %}
+{% endblock %}
diff --git a/src/OroCRM/Bundle/ContactUsBundle/Resources/views/ContactRequest/update.html.twig b/src/OroCRM/Bundle/ContactUsBundle/Resources/views/ContactRequest/update.html.twig
new file mode 100644
index 00000000000..e8e04462b7f
--- /dev/null
+++ b/src/OroCRM/Bundle/ContactUsBundle/Resources/views/ContactRequest/update.html.twig
@@ -0,0 +1,67 @@
+{% extends 'OroUIBundle:actions:update.html.twig' %}
+
+{% set formAction = form.vars.value.id ? path('orocrm_contactus_request_update', { 'id': form.vars.value.id }) : path('orocrm_contactus_request_create') %}
+{% set fullname = form.vars.value|oro_format_name|default('N/A') %}
+{% oro_title_set({ params : {"%request.clientName%": fullname} }) %}
+
+{% block navButtons %}
+ {% if form.vars.value.id and resource_granted('orocrm_contactus_request_delete') %}
+ {{ UI.deleteButton({
+ 'dataUrl': path('orocrm_contactus_request_delete', {'id': form.vars.value.id}),
+ 'dataRedirect': path('orocrm_contactus_request_index'),
+ 'aCss': 'no-hash remove-button',
+ 'id': 'btn-remove-contact-request-form',
+ 'dataId': form.vars.value.id,
+ 'entity_label': 'orocrm.contactus.contactrequest.entity_label'|trans,
+ }) }}
+ {{ UI.buttonSeparator() }}
+ {% endif %}
+ {{ UI.button({'path' : path('orocrm_contactus_request_index'), 'title' : 'Cancel'|trans, 'label' : 'Cancel'|trans}) }}
+ {% if resource_granted('orocrm_contactus_request_edit') %}
+ {{ UI.saveAndStayButton() }}
+ {% endif %}
+ {{ UI.saveAndCloseButton() }}
+{% endblock %}
+
+{% block pageHeader %}
+ {% if form.vars.value.id %}
+ {% set breadcrumbs = {
+ 'entity': form.vars.value,
+ 'indexPath': path('orocrm_contactus_request_index'),
+ 'indexLabel': 'orocrm.contactus.contactrequest.entity_plural_label'|trans,
+ 'entityTitle': fullname
+ } %}
+ {{ parent() }}
+ {% else %}
+ {% set title = 'New'|trans ~ ' ' ~ 'orocrm.contactus.contactrequest.entity_label'|trans|lower %}
+ {% include 'OroUIBundle::page_title_block.html.twig' %}
+ {% endif %}
+{% endblock pageHeader %}
+
+{% block content_data %}
+ {% set id = 'contact-request-form' %}
+
+ {% set dataBlocks = [{
+ 'title': 'General'|trans,
+ 'class': 'active',
+ 'subblocks': [
+ {
+ 'title': 'Request Information'|trans,
+ 'data': [
+ form_row(form.channel),
+ form_row(form.firstName),
+ form_row(form.lastName),
+ form_row(form.emailAddress),
+ form_row(form.phone),
+ form_row(form.comment)
+ ]
+ }
+ ]
+ }] %}
+
+ {% set data = {
+ 'formErrors': form_errors(form)? form_errors(form) : null,
+ 'dataBlocks': dataBlocks,
+ } %}
+ {{ parent() }}
+{% endblock content_data %}
diff --git a/src/OroCRM/Bundle/ContactUsBundle/Resources/views/ContactRequest/view.html.twig b/src/OroCRM/Bundle/ContactUsBundle/Resources/views/ContactRequest/view.html.twig
new file mode 100644
index 00000000000..49d1cda268e
--- /dev/null
+++ b/src/OroCRM/Bundle/ContactUsBundle/Resources/views/ContactRequest/view.html.twig
@@ -0,0 +1,60 @@
+{% extends 'OroUIBundle:actions:view.html.twig' %}
+{% import 'OroUIBundle::macros.html.twig' as ui %}
+{% set fullname = entity|oro_format_name|default('N/A') %}
+{% oro_title_set({ params : {"%request.clientName%": fullname} }) %}
+
+{% block pageHeader %}
+ {% set breadcrumbs = {
+ 'entity': entity,
+ 'indexPath': path('orocrm_contactus_request_index'),
+ 'indexLabel': 'orocrm.contactus.contactrequest.entity_plural_label'|trans,
+ 'entityTitle': fullname
+ } %}
+ {{ parent() }}
+{% endblock pageHeader %}
+
+{% block navButtons %}
+ {% if resource_granted('orocrm_contactus_request_delete') %}
+ {{ UI.deleteButton({
+ 'dataUrl': path('orocrm_contactus_request_delete', {'id': entity.id}),
+ 'dataRedirect': path('orocrm_contactus_request_index'),
+ 'aCss': 'no-hash remove-button',
+ 'id': 'btn-remove-contact-request-form',
+ 'dataId': entity.id,
+ 'entity_label': 'orocrm.contactus.contactrequest.entity_label'|trans,
+ }) }}
+ {{ UI.buttonSeparator() }}
+ {% endif %}
+
+ {{ UI.button({'path' : path('orocrm_contactus_request_index'), 'title' : 'Cancel'|trans, 'label' : 'Cancel'|trans}) }}
+ {% if resource_granted('orocrm_contactus_request_edit') %}
+ {{ UI.editButton({
+ 'path': path('orocrm_contactus_request_update', {'id': entity.id}),
+ 'entity_label': 'orocrm.contactus.contactrequest.entity_label'|trans,
+ }) }}
+ {% endif %}
+{% endblock %}
+
+{% block content_data %}
+ {% set contactRequestInformationWidget %}
+ {{ oro_widget_render({
+ 'widgetType': 'block',
+ 'url': path('orocrm_contactus_request_info', {id: entity.id}),
+ 'title': 'Request Information'|trans
+ }) }}
+ {% endset %}
+
+ {% set dataBlocks = [
+ {
+ 'title': 'General',
+ 'class': 'active',
+ 'subblocks': [
+ {'data': [contactRequestInformationWidget]}
+ ]
+ }
+ ] %}
+
+ {% set id = 'contactRequestView' %}
+ {% set data = {'dataBlocks': dataBlocks} %}
+ {{ parent() }}
+{% endblock %}
diff --git a/src/OroCRM/Bundle/ContactUsBundle/Resources/views/ContactRequest/widget/info.html.twig b/src/OroCRM/Bundle/ContactUsBundle/Resources/views/ContactRequest/widget/info.html.twig
new file mode 100644
index 00000000000..7bcf445ecb1
--- /dev/null
+++ b/src/OroCRM/Bundle/ContactUsBundle/Resources/views/ContactRequest/widget/info.html.twig
@@ -0,0 +1,15 @@
+{% import 'OroUIBundle::macros.html.twig' as ui %}
+{% import 'OroEmailBundle::macros.html.twig' as email %}
+
+
diff --git a/src/OroCRM/Bundle/ContactUsBundle/Resources/views/fields.html.twig b/src/OroCRM/Bundle/ContactUsBundle/Resources/views/fields.html.twig
new file mode 100644
index 00000000000..9a6f9e2e283
--- /dev/null
+++ b/src/OroCRM/Bundle/ContactUsBundle/Resources/views/fields.html.twig
@@ -0,0 +1,11 @@
+{% block form_row %}
+ {% spaceless %}
+
+ {% if label is not sameas(false) %}
+ {{ form_label(form, '' , { label_attr: label_attr }) }}
+ {% endif %}
+ {{ form_widget(form) }}
+ {{ form_errors(form) }}
+
+ {% endspaceless %}
+{% endblock form_row %}
diff --git a/src/OroCRM/Bundle/ContactUsBundle/Resources/views/form.html.twig b/src/OroCRM/Bundle/ContactUsBundle/Resources/views/form.html.twig
new file mode 100644
index 00000000000..b426f3011b6
--- /dev/null
+++ b/src/OroCRM/Bundle/ContactUsBundle/Resources/views/form.html.twig
@@ -0,0 +1,30 @@
+{% form_theme form with ['OroCRMContactUsBundle::fields.html.twig'] %}
+
+{{ form_start(form, {'attr': {'id': form.vars.name, 'novalidate': 'novalidate' }}) }}
+
+
+
+ {{ form_row(form.firstName) }}
+
+
+ {{ form_row(form.lastName) }}
+
+
+
+
+ {{ form_row(form.emailAddress) }}
+
+
+
+
+ {{ form_row(form.phone) }}
+
+
+
+ {{ form_row(form.comment) }}
+
+
+ {{ form_widget(form.submit) }}
+
+
+{{ form_end(form) }}
diff --git a/src/OroCRM/Bundle/ContactUsBundle/Tests/Unit/Form/ContactReasonTest.php b/src/OroCRM/Bundle/ContactUsBundle/Tests/Unit/Form/ContactReasonTest.php
new file mode 100644
index 00000000000..df5b01d25a8
--- /dev/null
+++ b/src/OroCRM/Bundle/ContactUsBundle/Tests/Unit/Form/ContactReasonTest.php
@@ -0,0 +1,23 @@
+assertNull($entity->getId());
+ $this->assertSame($label, $entity->getLabel());
+
+ $label2 = uniqid('label2');
+ $entity->setLabel($label2);
+
+ $this->assertSame($label2, $entity->getLabel());
+ $this->assertSame($label2, (string)$entity);
+ }
+}
diff --git a/src/OroCRM/Bundle/ContactUsBundle/Tests/Unit/Form/ContactRequestTest.php b/src/OroCRM/Bundle/ContactUsBundle/Tests/Unit/Form/ContactRequestTest.php
new file mode 100644
index 00000000000..58b22d3f2c6
--- /dev/null
+++ b/src/OroCRM/Bundle/ContactUsBundle/Tests/Unit/Form/ContactRequestTest.php
@@ -0,0 +1,127 @@
+getMock('OroCRM\Bundle\SalesBundle\Entity\Lead');
+ $opportunity = $this->getMock('OroCRM\Bundle\SalesBundle\Entity\Opportunity');
+ $call = $this->getMock('OroCRM\Bundle\CallBundle\Entity\Call');
+ $emailEntity = $this->getMock('Oro\Bundle\EmailBundle\Entity\Email');
+ $workflowStep = $this->getMock('Oro\Bundle\WorkflowBundle\Entity\WorkflowStep');
+ $workflowItem = $this->getMock('Oro\Bundle\WorkflowBundle\Entity\WorkflowItem');
+ /** @var Channel $channel */
+ $channel = $this->getMock('Oro\Bundle\IntegrationBundle\Entity\Channel');
+ $contactReason = $this->getMock(
+ 'OroCRM\Bundle\ContactUsBundle\Entity\ContactReason',
+ [],
+ [uniqid('label')]
+ );
+
+ $request = new ContactRequest();
+ $request->setComment($comment);
+ $request->setFeedback($feedback);
+ $request->setEmailAddress($email);
+ $request->setFirstName($firstName);
+ $request->setLastName($lastName);
+ $request->setPhone($phone);
+ $request->setOrganizationName($organizationName);
+ $request->setPreferredContactMethod($preferredContactMethod);
+
+ $request->setCreatedAt($createdAt);
+ $request->setUpdatedAt($updatedAt);
+
+
+ $this->assertNull($request->getWorkflowStep());
+ $this->assertNull($request->getWorkflowStep());
+ $this->assertNull($request->getChannel());
+ $this->assertNull($request->getContactReason());
+ $this->assertNull($request->getLead());
+ $this->assertNull($request->getOpportunity());
+ $this->assertFalse($request->hasCall($call));
+ $this->assertFalse($request->hasEmail($emailEntity));
+
+ $request->setLead($lead);
+ $request->setOpportunity($opportunity);
+ $request->addCall($call);
+ $request->addEmail($emailEntity);
+ $request->setChannel($channel);
+ $request->setContactReason($contactReason);
+ $request->setWorkflowItem($workflowItem);
+ $request->setWorkflowStep($workflowStep);
+
+ $this->assertNull($request->getId());
+ $this->assertSame($channel, $request->getChannel());
+ $this->assertSame($contactReason, $request->getContactReason());
+ $this->assertEquals($comment, $request->getComment());
+ $this->assertEquals($feedback, $request->getFeedback());
+ $this->assertEquals($organizationName, $request->getOrganizationName());
+ $this->assertEquals($email, $request->getEmailAddress());
+ $this->assertEquals($firstName, $request->getFirstName());
+ $this->assertEquals($lastName, $request->getLastName());
+ $this->assertEquals($phone, $request->getPhone());
+ $this->assertEquals($preferredContactMethod, $request->getPreferredContactMethod());
+ $this->assertEquals($createdAt, $request->getCreatedAt());
+ $this->assertEquals($updatedAt, $request->getUpdatedAt());
+ $this->assertSame($lead, $request->getLead());
+ $this->assertSame($opportunity, $request->getOpportunity());
+ $this->assertSame($workflowStep, $request->getWorkflowStep());
+ $this->assertSame($workflowItem, $request->getWorkflowItem());
+
+ // should not provoke fatal error, because it's not mandatory field
+ $request->setContactReason(null);
+
+ $request->removeCall($call);
+ $this->assertCount(0, $request->getCalls());
+ $request->removeEmail($emailEntity);
+ $this->assertCount(0, $request->getEmails());
+ }
+
+ public function testBeforeSave()
+ {
+ $request = new ContactRequest();
+
+ $this->assertNull($request->getCreatedAt());
+ $this->assertNull($request->getUpdatedAt());
+
+ $request->prePersist();
+ $this->assertNotNull($request->getCreatedAt());
+ $this->assertInstanceOf('DateTime', $request->getCreatedAt());
+ $this->assertNotNull($request->getUpdatedAt());
+ $this->assertInstanceOf('DateTime', $request->getUpdatedAt());
+ $this->assertSame($request->getCreatedAt(), $request->getUpdatedAt());
+ }
+
+ public function testDoPreUpdate()
+ {
+ $request = new ContactRequest();
+ $updatedAt = new \DateTime();
+ $request->setUpdatedAt($updatedAt);
+
+ $request->preUpdate();
+ $this->assertNotNull($request->getUpdatedAt());
+ $this->assertInstanceOf('DateTime', $request->getUpdatedAt());
+ $this->assertNotSame($updatedAt, $request->getUpdatedAt());
+ }
+}
diff --git a/src/OroCRM/Bundle/ContactUsBundle/Tests/Unit/Form/Handler/ContactRequestHandlerTest.php b/src/OroCRM/Bundle/ContactUsBundle/Tests/Unit/Form/Handler/ContactRequestHandlerTest.php
new file mode 100644
index 00000000000..54ab8d8913e
--- /dev/null
+++ b/src/OroCRM/Bundle/ContactUsBundle/Tests/Unit/Form/Handler/ContactRequestHandlerTest.php
@@ -0,0 +1,108 @@
+form = $this->getMockBuilder('Symfony\Component\Form\Form')
+ ->disableOriginalConstructor()->getMock();
+ $this->request = new Request();
+ $this->em = $this->getMockBuilder('Doctrine\ORM\EntityManager')
+ ->disableOriginalConstructor()->getMock();
+
+ $this->entity = new ContactRequest();
+ $this->handler = new ContactRequestHandler($this->form, $this->request, $this->em);
+ }
+
+ public function tearDown()
+ {
+ unset($this->form, $this->request, $this->em, $this->handler, $this->entity);
+ }
+
+ public function testProcessUnsupportedRequest()
+ {
+ $this->form->expects($this->once())->method('setData')
+ ->with($this->entity);
+
+ $this->form->expects($this->never())
+ ->method('submit');
+
+ $this->assertFalse($this->handler->process($this->entity));
+ }
+
+ /**
+ * @dataProvider supportedMethods
+ *
+ * @param string $method
+ */
+ public function testProcessSupportedRequest($method)
+ {
+ $this->form->expects($this->once())->method('setData')
+ ->with($this->entity);
+
+ $this->request->setMethod($method);
+
+ $this->form->expects($this->once())->method('submit')
+ ->with($this->request);
+
+ $this->assertFalse($this->handler->process($this->entity));
+ }
+
+ /**
+ * @return array
+ */
+ public function supportedMethods()
+ {
+ return [
+ ['POST'],
+ ['PUT']
+ ];
+ }
+
+
+ public function testProcessValidData()
+ {
+ $this->form->expects($this->once())->method('setData')
+ ->with($this->entity);
+
+ $this->request->setMethod('POST');
+
+ $this->form->expects($this->once())->method('submit')
+ ->with($this->request);
+
+ $this->form->expects($this->once())->method('isValid')
+ ->will($this->returnValue(true));
+
+ $this->em->expects($this->once())->method('persist')
+ ->with($this->entity);
+
+ $this->em->expects($this->once())->method('flush');
+
+ $this->assertTrue($this->handler->process($this->entity));
+ }
+}
diff --git a/src/OroCRM/Bundle/ContactUsBundle/Tests/Unit/Form/Type/ContactRequestTypeTest.php b/src/OroCRM/Bundle/ContactUsBundle/Tests/Unit/Form/Type/ContactRequestTypeTest.php
new file mode 100644
index 00000000000..c973222f206
--- /dev/null
+++ b/src/OroCRM/Bundle/ContactUsBundle/Tests/Unit/Form/Type/ContactRequestTypeTest.php
@@ -0,0 +1,126 @@
+formType = new ContactRequestType();
+ }
+
+ public function tearDown()
+ {
+ parent::tearDown();
+ unset($this->formType);
+ }
+
+ protected function getExtensions()
+ {
+ $mockEntityManager = $this->getMockBuilder('\Doctrine\ORM\EntityManager')
+ ->disableOriginalConstructor()->getMock();
+
+ $mockMetadata = $this->getMockBuilder('Doctrine\Common\Persistence\Mapping\ClassMetadata')
+ ->disableOriginalConstructor()->getMock();
+
+ $mockEntityManager->expects($this->any())->method('getClassMetadata')
+ ->will($this->returnValue($mockMetadata));
+
+ $mockRegistry = $this->getMockBuilder('Doctrine\Bundle\DoctrineBundle\Registry')
+ ->disableOriginalConstructor()
+ ->setMethods(['getManagerForClass'])
+ ->getMock();
+
+ $mockRegistry->expects($this->any())->method('getManagerForClass')
+ ->will($this->returnValue($mockEntityManager));
+
+ $mockEntityType = $this->getMockBuilder('Symfony\Bridge\Doctrine\Form\Type\EntityType')
+ ->setMethods(['getName', 'buildForm'])
+ ->setConstructorArgs([$mockRegistry])
+ ->getMock();
+
+ $mockEntityType->expects($this->any())->method('getName')
+ ->will($this->returnValue('entity'));
+
+ $mockRepo = $this->getMockBuilder('Doctrine\ORM\EntityRepository')
+ ->disableOriginalConstructor()
+ ->getMock();
+
+ $mockEntityManager->expects($this->any())
+ ->method('getRepository')
+ ->will($this->returnValue($mockRepo));
+
+ $mockRepo->expects($this->any())->method('findAll')
+ ->will($this->returnValue([]));
+
+ $parentType = new ChannelAwareFormType();
+
+ return [
+ new PreloadedExtension(
+ array(
+ $parentType->getName() => $parentType,
+ $mockEntityType->getName() => $mockEntityType
+ ),
+ array()
+ )
+ ];
+ }
+
+ public function testHasName()
+ {
+ $this->assertEquals('orocrm_contactus_contact_request', $this->formType->getName());
+ }
+
+ public function testHasChannelAwareParent()
+ {
+ $this->assertEquals('oro_channel_aware_form', $this->formType->getParent());
+ }
+
+ public function testImplementEmbeddedFormInterface()
+ {
+ $this->assertTrue($this->formType instanceof EmbeddedFormInterface);
+
+ $this->assertNotEmpty($this->formType->getDefaultCss());
+ $this->assertInternalType('string', $this->formType->getDefaultCss());
+
+ $this->assertNotEmpty($this->formType->getDefaultSuccessMessage());
+ $this->assertInternalType('string', $this->formType->getDefaultSuccessMessage());
+
+ $this->assertNotEmpty($this->formType->geFormLayout());
+ $this->assertInternalType('string', $this->formType->geFormLayout());
+ }
+
+ public function testBuildForm()
+ {
+ $form = $this->factory->create($this->formType, null);
+
+ $this->assertSame(
+ 'OroCRM\Bundle\ContactUsBundle\Entity\ContactRequest',
+ $form->getConfig()->getOption('data_class')
+ );
+
+ $fields = [
+ 'firstName',
+ 'lastName',
+ 'emailAddress',
+ 'phone',
+ 'comment',
+ 'submit'
+ ];
+ foreach ($fields as $field) {
+ $this->assertTrue($form->has($field), sprintf('Form should have: %s child', $field));
+ }
+ }
+}
diff --git a/src/OroCRM/Bundle/ContactUsBundle/Tests/Unit/Validator/ContactRequestCallbackValidatorTest.php b/src/OroCRM/Bundle/ContactUsBundle/Tests/Unit/Validator/ContactRequestCallbackValidatorTest.php
new file mode 100644
index 00000000000..5a7b02ed4e8
--- /dev/null
+++ b/src/OroCRM/Bundle/ContactUsBundle/Tests/Unit/Validator/ContactRequestCallbackValidatorTest.php
@@ -0,0 +1,87 @@
+setPhone($phone);
+ $request->setEmailAddress($email);
+ $request->setPreferredContactMethod($method);
+
+ $context = $this->getMockBuilder('Symfony\Component\Validator\ExecutionContext')
+ ->disableOriginalConstructor()->getMock();
+ $context->expects($this->exactly($expectedViolationCount))->method('addViolationAt');
+ ContactRequestCallbackValidator::validate($request, $context);
+ }
+
+ /**
+ * @return array
+ */
+ public function validationDataProvider()
+ {
+ return [
+ 'phone only required' => [
+ uniqid('phone'),
+ null,
+ ContactRequest::CONTACT_METHOD_PHONE,
+ 0
+ ],
+ 'phone only required, error if empty' => [
+ null,
+ null,
+ ContactRequest::CONTACT_METHOD_PHONE,
+ 1
+ ],
+ 'email only required' => [
+ null,
+ uniqid('email'),
+ ContactRequest::CONTACT_METHOD_EMAIL,
+ 0
+ ],
+ 'email only required, error if empty' => [
+ null,
+ null,
+ ContactRequest::CONTACT_METHOD_EMAIL,
+ 1
+ ],
+ 'both required' => [
+ null,
+ null,
+ ContactRequest::CONTACT_METHOD_BOTH,
+ 2
+ ],
+ 'both required, email given only' => [
+ null,
+ uniqid('email'),
+ ContactRequest::CONTACT_METHOD_BOTH,
+ 1
+ ],
+ 'both required, phone given only' => [
+ uniqid('phone'),
+ null,
+ ContactRequest::CONTACT_METHOD_BOTH,
+ 1
+ ],
+ 'both required, both given' => [
+ uniqid('phone'),
+ uniqid('email'),
+ ContactRequest::CONTACT_METHOD_BOTH,
+ 0
+ ],
+ ];
+ }
+}
diff --git a/src/OroCRM/Bundle/ContactUsBundle/Tests/bootstrap.php b/src/OroCRM/Bundle/ContactUsBundle/Tests/bootstrap.php
new file mode 100644
index 00000000000..fb30f1f067e
--- /dev/null
+++ b/src/OroCRM/Bundle/ContactUsBundle/Tests/bootstrap.php
@@ -0,0 +1,9 @@
+getPreferredContactMethod()) {
+ case ContactRequest::CONTACT_METHOD_PHONE:
+ $phoneError = !$object->getPhone();
+ break;
+ case ContactRequest::CONTACT_METHOD_EMAIL:
+ $emailError = !$object->getEmailAddress();
+ break;
+ case ContactRequest::CONTACT_METHOD_BOTH:
+ default:
+ $phoneError = !$object->getPhone();
+ $emailError = !$object->getEmailAddress();
+ }
+
+ if ($emailError) {
+ $context->addViolationAt('emailAddress', 'This value should not be blank.');
+ }
+ if ($phoneError) {
+ $context->addViolationAt('phone', 'This value should not be blank.');
+ }
+ }
+}
diff --git a/src/OroCRM/Bundle/ContactUsBundle/phpunit.xml.dist b/src/OroCRM/Bundle/ContactUsBundle/phpunit.xml.dist
new file mode 100644
index 00000000000..287c538a612
--- /dev/null
+++ b/src/OroCRM/Bundle/ContactUsBundle/phpunit.xml.dist
@@ -0,0 +1,31 @@
+
+
+
+
+
+
+ ./Tests
+
+
+
+
+
+ .
+
+ ./vendor
+ ./Resources
+ ./Tests
+
+
+
+
diff --git a/src/OroCRM/Bundle/DemoDataBundle/Migrations/DataFixtures/Demo/ORM/v1_0/LoadAccountData.php b/src/OroCRM/Bundle/DemoDataBundle/Migrations/DataFixtures/Demo/ORM/v1_0/LoadAccountData.php
index eabd804acc5..15a507d0a9e 100644
--- a/src/OroCRM/Bundle/DemoDataBundle/Migrations/DataFixtures/Demo/ORM/v1_0/LoadAccountData.php
+++ b/src/OroCRM/Bundle/DemoDataBundle/Migrations/DataFixtures/Demo/ORM/v1_0/LoadAccountData.php
@@ -4,6 +4,7 @@
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\DependencyInjection\ContainerAwareInterface;
+use Doctrine\Common\DataFixtures\DependentFixtureInterface;
use Doctrine\ORM\EntityManager;
use Doctrine\Common\DataFixtures\AbstractFixture;
use Doctrine\Common\Persistence\ObjectManager;
@@ -15,7 +16,7 @@
use Oro\Bundle\UserBundle\Entity\User;
use OroCRM\Bundle\AccountBundle\Entity\Account;
-class LoadAccountData extends AbstractFixture implements ContainerAwareInterface
+class LoadAccountData extends AbstractFixture implements ContainerAwareInterface, DependentFixtureInterface
{
/**
* @var ContainerInterface
@@ -35,6 +36,16 @@ class LoadAccountData extends AbstractFixture implements ContainerAwareInterface
*/
protected $countries;
+ /**
+ * {@inheritdoc}
+ */
+ public function getDependencies()
+ {
+ return [
+ 'OroCRM\Bundle\DemoDataBundle\Migrations\DataFixtures\Demo\ORM\v1_0\LoadUsersData'
+ ];
+ }
+
/**
* {@inheritDoc}
*/
diff --git a/src/OroCRM/Bundle/DemoDataBundle/Migrations/DataFixtures/Demo/ORM/v1_0/LoadLeadSourceData.php b/src/OroCRM/Bundle/DemoDataBundle/Migrations/DataFixtures/Demo/ORM/v1_0/LoadLeadSourceData.php
new file mode 100644
index 00000000000..41b44d077c9
--- /dev/null
+++ b/src/OroCRM/Bundle/DemoDataBundle/Migrations/DataFixtures/Demo/ORM/v1_0/LoadLeadSourceData.php
@@ -0,0 +1,67 @@
+ false,
+ 'Advertising' => false,
+ 'Blogging' => false,
+ 'Media' => false,
+ 'Outbound' => false,
+ 'Partner' => false
+ ];
+
+ /**
+ * @var ContainerInterface
+ */
+ protected $container;
+
+ /**
+ * {@inheritdoc}
+ */
+ public function setContainer(ContainerInterface $container = null)
+ {
+ $this->container = $container;
+ }
+
+ /**
+ * @param ObjectManager $manager
+ */
+ public function load(ObjectManager $manager)
+ {
+ /** @var ConfigManager $configManager */
+ $configManager = $this->container->get('oro_entity_config.config_manager');
+
+ $configFieldModel = $configManager->getConfigFieldModel(
+ 'OroCRM\Bundle\SalesBundle\Entity\Lead',
+ 'extend_source'
+ );
+
+ $priority = 1;
+ foreach ($this->data as $optionSetLabel => $isDefault) {
+ $priority++;
+ $optionSet = new OptionSet();
+ $optionSet
+ ->setLabel($optionSetLabel)
+ ->setIsDefault($isDefault)
+ ->setPriority($priority)
+ ->setField($configFieldModel);
+
+ $manager->persist($optionSet);
+ }
+
+ $manager->flush();
+ }
+}
diff --git a/src/OroCRM/Bundle/DemoDataBundle/Migrations/DataFixtures/Demo/ORM/v1_0/LoadLeadsData.php b/src/OroCRM/Bundle/DemoDataBundle/Migrations/DataFixtures/Demo/ORM/v1_0/LoadLeadsData.php
index 4ab6ce6ed09..b238ea545bf 100644
--- a/src/OroCRM/Bundle/DemoDataBundle/Migrations/DataFixtures/Demo/ORM/v1_0/LoadLeadsData.php
+++ b/src/OroCRM/Bundle/DemoDataBundle/Migrations/DataFixtures/Demo/ORM/v1_0/LoadLeadsData.php
@@ -1,8 +1,7 @@
false,
- 'Advertising' => false,
- 'Blogging' => false,
- 'Media' => false,
- 'Outbound' => false,
- 'Partner' => false
- ];
-
/**
* @var ContainerInterface
*/
@@ -68,8 +55,6 @@ class LoadLeadsData extends AbstractFixture implements ContainerAwareInterface,
/** @var ConfigManager */
protected $configManager;
- protected $leadExtendSourceConfigFieldModel;
-
/**
* {@inheritdoc}
*/
@@ -78,7 +63,8 @@ public function getDependencies()
return [
'OroCRM\Bundle\DemoDataBundle\Migrations\DataFixtures\Demo\ORM\v1_0\LoadUsersData',
'OroCRM\Bundle\DemoDataBundle\Migrations\DataFixtures\Demo\ORM\v1_0\LoadAccountData',
- 'OroCRM\Bundle\DemoDataBundle\Migrations\DataFixtures\Demo\ORM\v1_0\LoadAclData'
+ 'OroCRM\Bundle\DemoDataBundle\Migrations\DataFixtures\Demo\ORM\v1_0\LoadAclData',
+ 'OroCRM\Bundle\DemoDataBundle\Migrations\DataFixtures\Demo\ORM\v1_0\LoadLeadSourceData'
];
}
@@ -98,12 +84,6 @@ public function setContainer(ContainerInterface $container = null)
public function load(ObjectManager $manager)
{
$this->initSupportingEntities($manager);
-
- // TODO: We have to load lead sources here because when we do it in separate fixture an entity
- // config model is duplicated for Lead entity. Seems it because Doctrine ORMExecutor calls
- // "clear" method after loading each fixture
- $this->loadLeadSources();
-
$this->loadLeads();
$this->loadSources();
}
@@ -116,38 +96,20 @@ protected function initSupportingEntities(ObjectManager $manager = null)
$this->users = $this->em->getRepository('OroUserBundle:User')->findAll();
$this->countries = $this->em->getRepository('OroAddressBundle:Country')->findAll();
+ }
+ public function loadSources()
+ {
/** @var ConfigManager $configManager */
$configManager = $this->container->get('oro_entity_config.config_manager');
- $this->leadExtendSourceConfigFieldModel = $configManager->getConfigFieldModel(
+ $leadSourceConfigFieldModel = $configManager->getConfigFieldModel(
'OroCRM\Bundle\SalesBundle\Entity\Lead',
'extend_source'
);
- }
-
- public function loadLeadSources()
- {
- $priority = 1;
- foreach ($this->leadSources as $optionSetLabel => $isDefault) {
- $priority++;
- $optionSet = new OptionSet();
- $optionSet
- ->setLabel($optionSetLabel)
- ->setIsDefault($isDefault)
- ->setPriority($priority)
- ->setField($this->leadExtendSourceConfigFieldModel);
-
- $this->em->persist($optionSet);
- }
-
- $this->em->flush();
- }
- public function loadSources()
- {
/** @var OptionSet[] $sources */
- $sources = $this->leadExtendSourceConfigFieldModel->getOptions()->toArray();
+ $sources = $leadSourceConfigFieldModel->getOptions()->toArray();
$randomSource = count($sources)-1;
$leads = $this->em->getRepository('OroCRMSalesBundle:Lead')->findAll();
@@ -159,7 +121,7 @@ public function loadSources()
$optionSetRelation->setData(
null,
$lead->getId(),
- $this->leadExtendSourceConfigFieldModel,
+ $leadSourceConfigFieldModel,
$source
);
$this->persist($this->em, $optionSetRelation);
@@ -188,7 +150,6 @@ public function loadLeads()
$this->persist($this->em, $lead);
$this->loadSalesFlows($lead);
-
$i++;
if ($i % self::FLUSH_MAX == 0) {
$this->flush($this->em);
@@ -205,7 +166,9 @@ public function loadLeads()
*/
protected function loadSalesFlows(Lead $lead)
{
- $leadWorkflowItem = $this->workflowManager->startWorkflow(
+ $leadWorkflowItem = $this->startWorkflow(
+ $this->workflowManager,
+ $this->em,
'b2b_flow_lead',
$lead,
'qualify',
@@ -218,7 +181,9 @@ protected function loadSalesFlows(Lead $lead)
if ($this->getRandomBoolean()) {
/** @var Opportunity $opportunity */
$opportunity = $leadWorkflowItem->getResult()->get('opportunity');
- $salesFlowItem = $this->workflowManager->startWorkflow(
+ $salesFlowItem = $this->startWorkflow(
+ $this->workflowManager,
+ $this->em,
'b2b_flow_sales',
$opportunity,
'develop',
@@ -352,6 +317,36 @@ protected function transit($workflowManager, $workflowItem, $transition, array $
$workflowItem->setUpdated();
}
+ /**
+ * @param $workflowManager
+ * @param $em
+ * @param $workflow
+ * @param $entity
+ * @param null $transition
+ * @param array $data
+ *
+ * @return mixed
+ * @throws \Exception
+ */
+ protected function startWorkflow(
+ $workflowManager,
+ $em,
+ $workflow,
+ $entity,
+ $transition = null,
+ array $data = array()
+ ) {
+ /** @var Workflow $workflow */
+ $workflow = $workflowManager->getWorkflow($workflow);
+ try {
+ $workflowItem = $workflow->start($entity, $data, $transition);
+ $this->persist($em, $workflowItem);
+ } catch (\Exception $e) {
+ throw $e;
+ }
+ return $workflowItem;
+ }
+
/**
* Persist object
*
diff --git a/src/OroCRM/Bundle/DemoDataBundle/Migrations/DataFixtures/Demo/ORM/v1_0/LoadUsersData.php b/src/OroCRM/Bundle/DemoDataBundle/Migrations/DataFixtures/Demo/ORM/v1_0/LoadUsersData.php
index ad53574b3c0..93abfcbd638 100644
--- a/src/OroCRM/Bundle/DemoDataBundle/Migrations/DataFixtures/Demo/ORM/v1_0/LoadUsersData.php
+++ b/src/OroCRM/Bundle/DemoDataBundle/Migrations/DataFixtures/Demo/ORM/v1_0/LoadUsersData.php
@@ -45,7 +45,10 @@ class LoadUsersData extends AbstractFixture implements DependentFixtureInterface
*/
public function getDependencies()
{
- return ['OroCRM\Bundle\DemoDataBundle\Migrations\DataFixtures\Demo\ORM\v1_0\LoadBusinessUnitData'];
+ return [
+ 'OroCRM\Bundle\DemoDataBundle\Migrations\DataFixtures\Demo\ORM\v1_0\LoadBusinessUnitData',
+ 'OroCRM\Bundle\DemoDataBundle\Migrations\DataFixtures\Demo\ORM\v1_0\LoadUserData',
+ ];
}
/**
diff --git a/src/OroCRM/Bundle/MagentoBundle/Entity/Cart.php b/src/OroCRM/Bundle/MagentoBundle/Entity/Cart.php
index 935f47b3f0c..f8d641bf3ab 100644
--- a/src/OroCRM/Bundle/MagentoBundle/Entity/Cart.php
+++ b/src/OroCRM/Bundle/MagentoBundle/Entity/Cart.php
@@ -31,12 +31,13 @@
* )
* @Config(
* defaultValues={
+ * "entity"={"icon"="icon-shopping-cart"},
* "security"={
* "type"="ACL",
* "group_name"=""
* },
* "workflow"={
- * "primary"="b2c_flow_abandoned_shopping_cart"
+ * "active_workflow"="b2c_flow_abandoned_shopping_cart"
* }
* }
* )
@@ -418,7 +419,7 @@ public function setCustomer(Customer $customer = null)
/**
* @param CartAddress $shippingAddress
*/
- public function setShippingAddress(CartAddress $shippingAddress)
+ public function setShippingAddress($shippingAddress)
{
$this->shippingAddress = $shippingAddress;
}
@@ -426,7 +427,7 @@ public function setShippingAddress(CartAddress $shippingAddress)
/**
* @param CartAddress $billingAddress
*/
- public function setBillingAddress(CartAddress $billingAddress)
+ public function setBillingAddress($billingAddress)
{
$this->billingAddress = $billingAddress;
}
diff --git a/src/OroCRM/Bundle/MagentoBundle/Entity/CartAddress.php b/src/OroCRM/Bundle/MagentoBundle/Entity/CartAddress.php
index aae2f05e9bb..b03e92ba186 100644
--- a/src/OroCRM/Bundle/MagentoBundle/Entity/CartAddress.php
+++ b/src/OroCRM/Bundle/MagentoBundle/Entity/CartAddress.php
@@ -11,7 +11,11 @@
/**
* @ORM\Table("orocrm_magento_cart_address")
* @ORM\HasLifecycleCallbacks()
- * @Config()
+ * @Config(
+ * defaultValues={
+ * "entity"={"icon"="icon-map-marker"},
+ * }
+ * )
* @ORM\Entity
* @Oro\Loggable
*/
diff --git a/src/OroCRM/Bundle/MagentoBundle/Entity/CartStatus.php b/src/OroCRM/Bundle/MagentoBundle/Entity/CartStatus.php
index 08401ceaeee..e57c67ad0b4 100644
--- a/src/OroCRM/Bundle/MagentoBundle/Entity/CartStatus.php
+++ b/src/OroCRM/Bundle/MagentoBundle/Entity/CartStatus.php
@@ -30,8 +30,6 @@ public function __construct($name)
}
/**
- * Get type name
- *
* @return string
*/
public function getName()
@@ -40,8 +38,6 @@ public function getName()
}
/**
- * Set address type label
- *
* @param string $label
* @return CartStatus
*/
@@ -53,8 +49,6 @@ public function setLabel($label)
}
/**
- * Get address type label
- *
* @return string
*/
public function getLabel()
diff --git a/src/OroCRM/Bundle/MagentoBundle/Entity/Order.php b/src/OroCRM/Bundle/MagentoBundle/Entity/Order.php
index 595c1793ba2..d20d9bcbd94 100644
--- a/src/OroCRM/Bundle/MagentoBundle/Entity/Order.php
+++ b/src/OroCRM/Bundle/MagentoBundle/Entity/Order.php
@@ -30,7 +30,7 @@
* "group_name"=""
* },
* "workflow"={
- * "primary"="b2c_flow_order_follow_up"
+ * "active_workflow"="b2c_flow_order_follow_up"
* }
* }
* )
@@ -74,14 +74,14 @@ class Order extends BaseOrder
/**
* @var boolean
*
- * @ORM\Column(name="is_virtual", type="boolean")
+ * @ORM\Column(name="is_virtual", type="boolean", nullable=true)
*/
protected $isVirtual = false;
/**
* @var boolean
*
- * @ORM\Column(name="is_guest", type="boolean")
+ * @ORM\Column(name="is_guest", type="boolean", nullable=true)
*/
protected $isGuest = false;
@@ -102,35 +102,35 @@ class Order extends BaseOrder
/**
* @var string
*
- * @ORM\Column(name="store_name", type="string", length=255, nullable=false)
+ * @ORM\Column(name="store_name", type="string", length=255, nullable=true)
*/
protected $storeName;
/**
* @var float
*
- * @ORM\Column(name="total_paid_amount", type="float")
+ * @ORM\Column(name="total_paid_amount", type="float", nullable=true)
*/
protected $totalPaidAmount = 0;
/**
* @var float
*
- * @ORM\Column(name="total_invoiced_amount", type="float")
+ * @ORM\Column(name="total_invoiced_amount", type="float", nullable=true)
*/
protected $totalInvoicedAmount = 0;
/**
* @var float
*
- * @ORM\Column(name="total_refunded_amount", type="float")
+ * @ORM\Column(name="total_refunded_amount", type="float", nullable=true)
*/
protected $totalRefundedAmount = 0;
/**
* @var float
*
- * @ORM\Column(name="total_canceled_amount", type="float")
+ * @ORM\Column(name="total_canceled_amount", type="float", nullable=true)
*/
protected $totalCanceledAmount = 0;
diff --git a/src/OroCRM/Bundle/MagentoBundle/Entity/OrderItem.php b/src/OroCRM/Bundle/MagentoBundle/Entity/OrderItem.php
index 77ec05f8d8a..c21445f7a54 100644
--- a/src/OroCRM/Bundle/MagentoBundle/Entity/OrderItem.php
+++ b/src/OroCRM/Bundle/MagentoBundle/Entity/OrderItem.php
@@ -25,7 +25,7 @@ class OrderItem extends BaseOrderItem
/**
* @var string
*
- * @ORM\Column(name="product_type", type="string", length=255, nullable=false)
+ * @ORM\Column(name="product_type", type="string", length=255, nullable=true)
*/
protected $productType;
@@ -39,14 +39,14 @@ class OrderItem extends BaseOrderItem
/**
* @var boolean
*
- * @ORM\Column(name="is_virtual", type="boolean")
+ * @ORM\Column(name="is_virtual", type="boolean", nullable=true)
*/
protected $isVirtual;
/**
* @var float
*
- * @ORM\Column(name="original_price", type="float", nullable=false)
+ * @ORM\Column(name="original_price", type="float", nullable=true)
*/
protected $originalPrice;
diff --git a/src/OroCRM/Bundle/MagentoBundle/ImportExport/Serializer/CustomerDenormalizer.php b/src/OroCRM/Bundle/MagentoBundle/ImportExport/Serializer/CustomerDenormalizer.php
index fc45d12e51e..59198c11dac 100644
--- a/src/OroCRM/Bundle/MagentoBundle/ImportExport/Serializer/CustomerDenormalizer.php
+++ b/src/OroCRM/Bundle/MagentoBundle/ImportExport/Serializer/CustomerDenormalizer.php
@@ -17,28 +17,52 @@
class CustomerDenormalizer extends AbstractNormalizer implements DenormalizerInterface
{
- protected $importFieldsMap
- = [
- 'customer_id' => 'origin_id',
- 'firstname' => 'first_name',
- 'lastname' => 'last_name',
- 'middlename' => 'middle_name',
- 'prefix' => 'name_prefix',
- 'suffix' => 'name_suffix',
- 'dob' => 'birthday',
- 'taxvat' => 'vat',
- ];
-
- static protected $objectFields
- = [
- 'store',
- 'website',
- 'group',
- 'addresses',
- 'updatedAt',
- 'createdAt',
- 'birthday'
- ];
+ /**
+ * @var array
+ */
+ protected $importFieldsMap = array(
+ 'customer_id' => 'origin_id',
+ 'firstname' => 'first_name',
+ 'lastname' => 'last_name',
+ 'middlename' => 'middle_name',
+ 'prefix' => 'name_prefix',
+ 'suffix' => 'name_suffix',
+ 'dob' => 'birthday',
+ 'taxvat' => 'vat',
+ );
+
+ /**
+ * @var array
+ */
+ protected $addressBapToMageMapping = array(
+ 'namePrefix' => 'prefix',
+ 'firstName' => 'firstname',
+ 'middleName' => 'middlename',
+ 'lastName' => 'lastname',
+ 'nameSuffix' => 'suffix',
+ 'organization' => 'company',
+ 'street' => 'street',
+ 'city' => 'city',
+ 'postalCode' => 'postcode',
+ 'country' => 'country_id',
+ 'regionText' => 'region',
+ 'region' => 'region_id',
+ 'created' => 'created_at',
+ 'updated' => 'updated_at'
+ );
+
+ /**
+ * @var array
+ */
+ static protected $objectFields = array(
+ 'store',
+ 'website',
+ 'group',
+ 'addresses',
+ 'updatedAt',
+ 'createdAt',
+ 'birthday'
+ );
/**
* For importing customers
@@ -172,41 +196,27 @@ protected function setObjectFieldsValues(Customer $object, array $data, $format
}
/**
+ * @todo Move to converter CRM-789
* @param $data
- *
* @return array
*/
protected function formatAccountData($data)
{
- /**
- * @TODO FIXME move to converter
- */
-
- $account = [];
-
- $account['name'] = sprintf("%s %s", $data['first_name'], $data['last_name']);
+ $account = array(
+ 'name' => sprintf("%s %s", $data['first_name'], $data['last_name'])
+ );
foreach ($data['addresses'] as $address) {
- $types = [];
+ $addressTypes = array();
if (!empty($address['is_default_shipping'])) {
- $types[] = AddressType::TYPE_SHIPPING . '_address';
+ $addressTypes[] = AddressType::TYPE_SHIPPING . '_address';
}
if (!empty($address['is_default_billing'])) {
- $types[] = AddressType::TYPE_BILLING . '_address';
+ $addressTypes[] = AddressType::TYPE_BILLING . '_address';
}
- foreach ($types as $type) {
- $account[$type]['firstName'] = $address['firstname'];
- $account[$type]['lastName'] = $address['lastname'];
- $account[$type]['street'] = $address['street'];
- $account[$type]['city'] = $address['city'];
-
- $account[$type]['postalCode'] = $address['postcode'];
- $account[$type]['country'] = $address['country_id'];
- $account[$type]['regionText'] = isset($address['region']) ? $address['region'] : null;
- $account[$type]['region'] = isset($address['region_id']) ? $address['region_id'] : null;
- $account[$type]['created'] = $address['created_at'];
- $account[$type]['updated'] = $address['updated_at'];
+ foreach ($addressTypes as $addressType) {
+ $account[$addressType] = $this->getBapAddressData($address);
}
}
@@ -214,18 +224,14 @@ protected function formatAccountData($data)
}
/**
+ * @todo Move to converter CRM-789
* @param $data
- *
* @return array
*/
protected function formatContactData($data)
{
- /**
- * @TODO FIXME move to converter
- */
-
- $contact = $this->convertToCamelCase($data);
- $contactFieldNames = [
+ $contact = $this->convertToCamelCase($data);
+ $contactFieldNames = array(
'firstName' => null,
'lastName' => null,
'middleName' => null,
@@ -236,63 +242,31 @@ protected function formatContactData($data)
'birthday' => null,
'phones' => [],
'emails' => [],
- ];
+ );
// fill default values
$contact = array_merge($contactFieldNames, $contact);
- $addressFields = [
- 'firstName' => null,
- 'lastName' => null,
- 'middleName' => null,
- 'namePrefix' => null,
- 'nameSuffix' => null,
- 'postalCode' => null,
- 'country' => null,
- 'region' => null,
- 'regionText' => null,
- 'created' => null,
- 'updated' => null,
- 'types' => []
- ];
- $addressFieldsMap = [
- 'region' => 'regionText',
- 'regionId' => 'region',
- 'countryId' => 'country',
- 'createdAt' => 'created',
- 'updatedAt' => 'updated',
- 'postcode' => 'postalCode'
- ];
- $namesMap = [
- 'firstname' => 'first_name',
- 'lastname' => 'last_name',
- 'middlename' => 'middle_name',
- 'prefix' => 'name_prefix',
- 'suffix' => 'name_suffix',
- ];
-
foreach ($contact['addresses'] as $key => $address) {
- // process keys that will not be camelized correctly
- $address = $this->mapParams($namesMap, $address);
- $address = $this->convertToCamelCase($address);
- $address = $this->mapParams($addressFieldsMap, $address);
- $address = array_merge($addressFields, $address);
- //merge firstName and lastName from contact in case when it's not filled in address
- $address = array_merge(array_intersect_key(array_flip(['firstName', 'lastName']), $contact), $address);
+ $bapAddress = $this->getBapAddressData(
+ $address,
+ array(
+ 'firstName' => $contact['firstName'],
+ 'lastName' => $contact['lastName']
+ )
+ );
// prepare address types
- if (!empty($address['isDefaultShipping'])) {
- $address['types'][] = AddressType::TYPE_SHIPPING;
+ if (!empty($address['is_default_shipping'])) {
+ $bapAddress['types'][] = AddressType::TYPE_SHIPPING;
}
- if (!empty($address['isDefaultBilling'])) {
- $address['types'][] = AddressType::TYPE_BILLING;
+ if (!empty($address['is_default_billing'])) {
+ $bapAddress['types'][] = AddressType::TYPE_BILLING;
}
- if (!empty($address['telephone'])
- && !in_array($address['telephone'], $contact['phones'])
- ) {
+ if (!empty($address['telephone']) && !in_array($address['telephone'], $contact['phones'])) {
$contact['phones'][] = $address['telephone'];
}
- $contact['addresses'][$key] = $address;
+ $contact['addresses'][$key] = $bapAddress;
}
$contact['emails'][] = $contact['email'];
@@ -301,6 +275,36 @@ protected function formatContactData($data)
return $contact;
}
+ /**
+ * Get BAP address data based on magento address data.
+ *
+ * @param array $address
+ * @param array $defaultValues
+ * @return array
+ */
+ protected function getBapAddressData(array $address, array $defaultValues = array())
+ {
+ $bapAddress = array();
+ foreach ($this->addressBapToMageMapping as $bapKey => $mageKey) {
+ if (array_key_exists($mageKey, $address)) {
+ $bapAddress[$bapKey] = $address[$mageKey];
+ } else {
+ $bapAddress[$bapKey] = null;
+ }
+
+ if (array_key_exists($bapKey, $defaultValues) && empty($bapAddress[$bapKey])) {
+ $bapAddress[$bapKey] = $defaultValues[$bapKey];
+ }
+ }
+
+ // Magento API return address as $street1 . "\n" . $street2
+ if (strpos($bapAddress['street'], "\n") !== false) {
+ list($bapAddress['street'], $bapAddress['street2']) = explode("\n", $bapAddress['street']);
+ }
+
+ return $bapAddress;
+ }
+
/**
* @param array $data
* @param string $name
@@ -334,26 +338,4 @@ public function supportsDenormalization($data, $type, $format = null)
{
return is_array($data) && $type == MagentoConnectorInterface::CUSTOMER_TYPE;
}
-
- /**
- * Process params mapping
- *
- * @param array $map
- * @param array $params
- *
- * @return array
- */
- protected function mapParams($map, $params)
- {
- $keys = [];
- foreach (array_keys($params) as $key) {
- if (isset($map[$key])) {
- $keys[] = $map[$key];
- } else {
- $keys[] = $key;
- }
- }
-
- return array_combine($keys, array_values($params));
- }
}
diff --git a/src/OroCRM/Bundle/MagentoBundle/ImportExport/Strategy/BaseStrategy.php b/src/OroCRM/Bundle/MagentoBundle/ImportExport/Strategy/BaseStrategy.php
index 1e9ef0e8116..16e78baacd1 100644
--- a/src/OroCRM/Bundle/MagentoBundle/ImportExport/Strategy/BaseStrategy.php
+++ b/src/OroCRM/Bundle/MagentoBundle/ImportExport/Strategy/BaseStrategy.php
@@ -2,12 +2,15 @@
namespace OroCRM\Bundle\MagentoBundle\ImportExport\Strategy;
+use Doctrine\Common\Persistence\ManagerRegistry;
use Doctrine\Common\Util\ClassUtils;
use Doctrine\ORM\EntityRepository;
+use Doctrine\ORM\Mapping\ClassMetadataInfo;
use Doctrine\ORM\UnitOfWork;
use Oro\Bundle\AddressBundle\Entity\AbstractAddress;
use Oro\Bundle\AddressBundle\Entity\AbstractTypedAddress;
+use Oro\Bundle\AddressBundle\Entity\Country;
use Oro\Bundle\BatchBundle\Item\InvalidItemException;
use Oro\Bundle\ImportExportBundle\Context\ContextAwareInterface;
use Oro\Bundle\ImportExportBundle\Context\ContextInterface;
@@ -21,6 +24,9 @@ abstract class BaseStrategy implements StrategyInterface, ContextAwareInterface
/** @var ImportStrategyHelper */
protected $strategyHelper;
+ /** @var ManagerRegistry */
+ protected $managerRegistry;
+
/** @var ContextInterface */
protected $context;
@@ -35,10 +41,14 @@ abstract class BaseStrategy implements StrategyInterface, ContextAwareInterface
/**
* @param ImportStrategyHelper $strategyHelper
+ * @param ManagerRegistry $managerRegistry
*/
- public function __construct(ImportStrategyHelper $strategyHelper)
- {
- $this->strategyHelper = $strategyHelper;
+ public function __construct(
+ ImportStrategyHelper $strategyHelper,
+ ManagerRegistry $managerRegistry
+ ) {
+ $this->strategyHelper = $strategyHelper;
+ $this->managerRegistry = $managerRegistry;
}
/**
@@ -50,10 +60,10 @@ public function setImportExportContext(ContextInterface $context)
}
/**
- * @param mixed $entity
- * @param string $entityName
- * @param string|array $criteria
- * @param array $excludedProperties
+ * @param mixed $entity New entity
+ * @param string $entityName Class name
+ * @param string|array $criteria Fieldname to find existing entity
+ * @param array $excludedProperties Excluded properties
*
* @return mixed
*/
@@ -63,14 +73,27 @@ protected function findAndReplaceEntity($entity, $entityName, $criteria = 'id',
$existingEntity = $this->getEntityByCriteria($criteria, $entity);
} else {
$existingEntity = $this->getEntityOrNull($entity, $criteria, $entityName);
-
}
if ($existingEntity) {
$this->strategyHelper->importEntity($existingEntity, $entity, $excludedProperties);
$entity = $existingEntity;
} else {
- $entity->setId(null);
+ /* @var ClassMetadataInfo $metadata */
+ $metadata = $this
+ ->managerRegistry
+ ->getManagerForClass($entityName)
+ ->getClassMetadata($entityName);
+
+ $identifier = $metadata->getSingleIdentifierFieldName();
+ $setterMethod = 'set' . ucfirst($identifier);
+ if (method_exists($entity, $setterMethod)) {
+ $entity->$setterMethod(null);
+ } elseif (property_exists($entity, $identifier)) {
+ $reflection = new \ReflectionProperty(ClassUtils::getClass($entity), $identifier);
+ $reflection->setAccessible(true);
+ $reflection->setValue($entity, null);
+ }
}
return $entity;
@@ -183,10 +206,16 @@ protected function merge($entity)
*/
protected function updateAddressCountryRegion(AbstractAddress $address, $mageRegionId)
{
- $countryCode = $address->getCountry()->getIso2Code();
+ if (!$address->getCountry()) {
+ return $this;
+ }
+ $countryCode = $address->getCountry()->getIso2Code();
$country = $this->getAddressCountryByCode($address, $countryCode);
$address->setCountry($country);
+ if (!$country) {
+ return $this;
+ }
if (!empty($mageRegionId) && empty($this->mageRegionsCache[$mageRegionId])) {
$this->mageRegionsCache[$mageRegionId] = $this->getEntityByCriteria(
@@ -201,7 +230,7 @@ protected function updateAddressCountryRegion(AbstractAddress $address, $mageReg
$combinedCode = $mageRegion->getCombinedCode();
$regionCode = $mageRegion->getCode();
- if (empty($this->regionsCache[$combinedCode])) {
+ if (!array_key_exists($combinedCode, $this->regionsCache)) {
$this->regionsCache[$combinedCode] = $this->loadRegionByCode($combinedCode, $countryCode, $regionCode);
}
@@ -298,21 +327,27 @@ protected function updateAddressTypes(AbstractTypedAddress $address)
* @param string $countryCode
*
* @throws InvalidItemException
- * @return object
+ * @return object|null
*/
protected function getAddressCountryByCode(AbstractAddress $address, $countryCode)
{
- $this->countriesCache[$countryCode] = empty($this->countriesCache[$countryCode])
- ? $this->findAndReplaceEntity(
+ if (!$address->getCountry()) {
+ return null;
+ }
+
+ if (array_key_exists($countryCode, $this->countriesCache)) {
+ if (!empty($this->countriesCache[$countryCode])) {
+ $this->countriesCache[$countryCode] = $this->merge($this->countriesCache[$countryCode]);
+ }
+ } else {
+ /** @var Country $country */
+ $country = $this->findAndReplaceEntity(
$address->getCountry(),
'Oro\Bundle\AddressBundle\Entity\Country',
'iso2Code',
['iso2Code', 'iso3Code', 'name']
- )
- : $this->merge($this->countriesCache[$countryCode]);
-
- if (empty($this->countriesCache[$countryCode])) {
- throw new InvalidItemException(sprintf('Unable to find country by code "%s"', $countryCode), []);
+ );
+ $this->countriesCache[$countryCode] = $country->getIso2Code() ? $country : null;
}
return $this->countriesCache[$countryCode];
diff --git a/src/OroCRM/Bundle/MagentoBundle/ImportExport/Strategy/CartStrategy.php b/src/OroCRM/Bundle/MagentoBundle/ImportExport/Strategy/CartStrategy.php
index 2c16eaaabea..eb09c2de3fd 100644
--- a/src/OroCRM/Bundle/MagentoBundle/ImportExport/Strategy/CartStrategy.php
+++ b/src/OroCRM/Bundle/MagentoBundle/ImportExport/Strategy/CartStrategy.php
@@ -5,8 +5,8 @@
use Doctrine\Common\Collections\ArrayCollection;
use OroCRM\Bundle\MagentoBundle\Entity\Cart;
+use OroCRM\Bundle\MagentoBundle\Entity\CartAddress;
use OroCRM\Bundle\MagentoBundle\Entity\Customer;
-use Oro\Bundle\ImportExportBundle\Strategy\Import\ImportStrategyHelper;
class CartStrategy extends BaseStrategy
{
@@ -15,9 +15,11 @@ class CartStrategy extends BaseStrategy
/** @var StoreStrategy */
protected $storeStrategy;
- public function __construct(ImportStrategyHelper $strategyHelper, StoreStrategy $storeStrategy)
+ /**
+ * @param StoreStrategy $storeStrategy
+ */
+ public function setStoreStrategy(StoreStrategy $storeStrategy)
{
- parent::__construct($strategyHelper);
$this->storeStrategy = $storeStrategy;
}
@@ -146,6 +148,7 @@ protected function updateAddresses(Cart $newCart, Cart $importedCart)
foreach ($addresses as $addressName) {
$addressGetter = 'get'.$addressName;
$setter = 'set'.$addressName;
+ /** @var CartAddress $address */
$address = $importedCart->$addressGetter();
if (!$address) {
@@ -163,7 +166,11 @@ protected function updateAddresses(Cart $newCart, Cart $importedCart)
}
$this->updateAddressCountryRegion($address, $mageRegionId);
- $newCart->$setter($address);
+ if ($address->getCountry()) {
+ $newCart->$setter($address);
+ } else {
+ $newCart->$setter(null);
+ }
}
return $this;
diff --git a/src/OroCRM/Bundle/MagentoBundle/ImportExport/Strategy/CustomerStrategy.php b/src/OroCRM/Bundle/MagentoBundle/ImportExport/Strategy/CustomerStrategy.php
index c0fa169844a..c5fcafe44bc 100644
--- a/src/OroCRM/Bundle/MagentoBundle/ImportExport/Strategy/CustomerStrategy.php
+++ b/src/OroCRM/Bundle/MagentoBundle/ImportExport/Strategy/CustomerStrategy.php
@@ -161,9 +161,13 @@ protected function updateContact(Customer $entity, Contact $contact)
//$originAddressId = $address->getId();
$address->setId(null);
- $this
- ->updateAddressCountryRegion($address, $mageRegionId)
- ->updateAddressTypes($address);
+ $this->updateAddressCountryRegion($address, $mageRegionId);
+ if (!$address->getCountry()) {
+ $contact->removeAddress($address);
+ continue;
+ }
+
+ $this->updateAddressTypes($address);
}
$entity->setContact($contact);
@@ -186,16 +190,21 @@ protected function updateAddresses(Customer $entity, Collection $addresses)
$originAddressId = $address->getId();
$address->setOriginId($originAddressId);
- $existingAddress = $entity->getAddressByOriginId($originAddressId);
+ if ($originAddressId) {
+ $existingAddress = $entity->getAddressByOriginId($originAddressId);
+ if ($existingAddress) {
+ $this->strategyHelper->importEntity($existingAddress, $address, ['id', 'region', 'country']);
+ $address = $existingAddress;
+ }
+ }
- if ($existingAddress) {
- $this->strategyHelper->importEntity($existingAddress, $address, ['id', 'region', 'country']);
- $address = $existingAddress;
+ $this->updateAddressCountryRegion($address, $mageRegionId);
+ if (!$address->getCountry()) {
+ $entity->removeAddress($address);
+ continue;
}
- $this
- ->updateAddressCountryRegion($address, $mageRegionId)
- ->updateAddressTypes($address);
+ $this->updateAddressTypes($address);
$address->setOwner($entity);
$entity->addAddress($address);
@@ -235,7 +244,11 @@ protected function updateAccount(Customer $entity, Account $account)
$mageRegionId = $address->getRegion() ? $address->getRegion()->getCode() : null;
$this->updateAddressCountryRegion($address, $mageRegionId);
- $account->{'set' . ucfirst($key) . 'Address'}($address);
+ if ($address->getCountry()) {
+ $account->{'set' . ucfirst($key) . 'Address'}($address);
+ } else {
+ $account->{'set' . ucfirst($key) . 'Address'}(null);
+ }
}
$entity->setAccount($account);
diff --git a/src/OroCRM/Bundle/MagentoBundle/ImportExport/Strategy/OrderStrategy.php b/src/OroCRM/Bundle/MagentoBundle/ImportExport/Strategy/OrderStrategy.php
index 5c2580826d0..0965862209d 100644
--- a/src/OroCRM/Bundle/MagentoBundle/ImportExport/Strategy/OrderStrategy.php
+++ b/src/OroCRM/Bundle/MagentoBundle/ImportExport/Strategy/OrderStrategy.php
@@ -2,8 +2,6 @@
namespace OroCRM\Bundle\MagentoBundle\ImportExport\Strategy;
-use Oro\Bundle\ImportExportBundle\Strategy\Import\ImportStrategyHelper;
-
use OroCRM\Bundle\MagentoBundle\Entity\Cart;
use OroCRM\Bundle\MagentoBundle\Entity\Customer;
use OroCRM\Bundle\MagentoBundle\Entity\Order;
@@ -19,9 +17,11 @@ class OrderStrategy extends BaseStrategy
/** @var StoreStrategy */
protected $storeStrategy;
- public function __construct(ImportStrategyHelper $strategyHelper, StoreStrategy $storeStrategy)
+ /**
+ * @param StoreStrategy $storeStrategy
+ */
+ public function setStoreStrategy(StoreStrategy $storeStrategy)
{
- parent::__construct($strategyHelper);
$this->storeStrategy = $storeStrategy;
}
@@ -129,6 +129,11 @@ protected function processAddresses(Order $entityToUpdate, Order $entityToImport
}
$this->updateAddressCountryRegion($address, $mageRegionId);
+ if (!$address->getCountry()) {
+ $entityToUpdate->getAddresses()->offsetUnset($k);
+ continue;
+ }
+
$this->updateAddressTypes($address);
$address->setOwner($entityToUpdate);
diff --git a/src/OroCRM/Bundle/MagentoBundle/Migrations/DataFixtures/ORM/v1_2/LoadMagentoCountryData.php b/src/OroCRM/Bundle/MagentoBundle/Migrations/DataFixtures/ORM/v1_2/LoadMagentoCountryData.php
new file mode 100644
index 00000000000..2d9e652282b
--- /dev/null
+++ b/src/OroCRM/Bundle/MagentoBundle/Migrations/DataFixtures/ORM/v1_2/LoadMagentoCountryData.php
@@ -0,0 +1,19 @@
+structureFileName;
+ $fileName = str_replace('/', DIRECTORY_SEPARATOR, $fileName);
+
+ return $fileName;
+ }
+}
diff --git a/src/OroCRM/Bundle/MagentoBundle/Migrations/DataFixtures/ORM/v1_2/data/countries.yml b/src/OroCRM/Bundle/MagentoBundle/Migrations/DataFixtures/ORM/v1_2/data/countries.yml
new file mode 100644
index 00000000000..fbe905a6633
--- /dev/null
+++ b/src/OroCRM/Bundle/MagentoBundle/Migrations/DataFixtures/ORM/v1_2/data/countries.yml
@@ -0,0 +1,180 @@
+AI:
+ iso2Code: AI
+ iso3Code: AIA
+ regions: { }
+AN:
+ iso2Code: AN
+ iso3Code: ANT
+ regions: { }
+AQ:
+ iso2Code: AQ
+ iso3Code: ATA
+ regions: { }
+AS:
+ iso2Code: AS
+ iso3Code: ASM
+ regions: { }
+AW:
+ iso2Code: AW
+ iso3Code: ABW
+ regions: { }
+AX:
+ iso2Code: AX
+ iso3Code: ALA
+ regions: { }
+BM:
+ iso2Code: BM
+ iso3Code: BMU
+ regions: { }
+BV:
+ iso2Code: BV
+ iso3Code: BVT
+ regions: { }
+CC:
+ iso2Code: CC
+ iso3Code: CCK
+ regions: { }
+CK:
+ iso2Code: CK
+ iso3Code: COK
+ regions: { }
+CX:
+ iso2Code: CX
+ iso3Code: CXR
+ regions: { }
+EH:
+ iso2Code: EH
+ iso3Code: ESH
+ regions: { }
+FK:
+ iso2Code: FK
+ iso3Code: FLK
+ regions: { }
+FO:
+ iso2Code: FO
+ iso3Code: FRO
+ regions: { }
+GF:
+ iso2Code: GF
+ iso3Code: GUF
+ regions: { }
+GI:
+ iso2Code: GI
+ iso3Code: GIB
+ regions: { }
+GP:
+ iso2Code: GP
+ iso3Code: GLP
+ regions: { }
+GS:
+ iso2Code: GS
+ iso3Code: SGS
+ regions: { }
+GU:
+ iso2Code: GU
+ iso3Code: GUM
+ regions: { }
+HK:
+ iso2Code: HK
+ iso3Code: HKG
+ regions: { }
+HM:
+ iso2Code: HM
+ iso3Code: HMD
+ regions: { }
+IO:
+ iso2Code: IO
+ iso3Code: IOT
+ regions: { }
+KY:
+ iso2Code: KY
+ iso3Code: CYM
+ regions: { }
+LC:
+ iso2Code: LC
+ iso3Code: LCA
+ regions: { }
+MC:
+ iso2Code: MC
+ iso3Code: MCO
+ regions: { }
+MP:
+ iso2Code: MP
+ iso3Code: MNP
+ regions: { }
+MQ:
+ iso2Code: MQ
+ iso3Code: MTQ
+ regions: { }
+MS:
+ iso2Code: MS
+ iso3Code: MSR
+ regions: { }
+NC:
+ iso2Code: NC
+ iso3Code: NCL
+ regions: { }
+NF:
+ iso2Code: NF
+ iso3Code: NFK
+ regions: { }
+NU:
+ iso2Code: NU
+ iso3Code: NIU
+ regions: { }
+PF:
+ iso2Code: PF
+ iso3Code: PYF
+ regions: { }
+PM:
+ iso2Code: PM
+ iso3Code: SPM
+ regions: { }
+PN:
+ iso2Code: PN
+ iso3Code: PCN
+ regions: { }
+PR:
+ iso2Code: PR
+ iso3Code: PRI
+ regions: { }
+RE:
+ iso2Code: RE
+ iso3Code: REU
+ regions: { }
+SJ:
+ iso2Code: SJ
+ iso3Code: SJM
+ regions: { }
+TC:
+ iso2Code: TC
+ iso3Code: TCA
+ regions: { }
+TF:
+ iso2Code: TF
+ iso3Code: ATF
+ regions: { }
+TK:
+ iso2Code: TK
+ iso3Code: TKL
+ regions: { }
+VA:
+ iso2Code: VA
+ iso3Code: VAT
+ regions: { }
+VG:
+ iso2Code: VG
+ iso3Code: VGB
+ regions: { }
+VI:
+ iso2Code: VI
+ iso3Code: VIR
+ regions: { }
+WF:
+ iso2Code: WF
+ iso3Code: WLF
+ regions: { }
+YT:
+ iso2Code: YT
+ iso3Code: MYT
+ regions: { }
diff --git a/src/OroCRM/Bundle/MagentoBundle/Resources/config/datagrid.yml b/src/OroCRM/Bundle/MagentoBundle/Resources/config/datagrid.yml
index 1da7ced5aa6..41c9790ea5f 100644
--- a/src/OroCRM/Bundle/MagentoBundle/Resources/config/datagrid.yml
+++ b/src/OroCRM/Bundle/MagentoBundle/Resources/config/datagrid.yml
@@ -100,6 +100,7 @@ datagrid:
rowAction: true
options:
entityHint: customer
+ export: true
magento-cart-grid:
source:
@@ -227,6 +228,7 @@ datagrid:
rowAction: true
options:
entityHint: cart
+ export: true
magento-cartitem-grid:
source:
@@ -437,7 +439,6 @@ datagrid:
options:
entityHint: product
-
magento-order-grid:
source:
type: orm
@@ -557,6 +558,7 @@ datagrid:
rowAction: true
options:
entityHint: order
+ export: true
magento-orderitem-grid:
source:
diff --git a/src/OroCRM/Bundle/MagentoBundle/Resources/config/importexport.yml b/src/OroCRM/Bundle/MagentoBundle/Resources/config/importexport.yml
index 57d4d7334d5..24c151495f0 100644
--- a/src/OroCRM/Bundle/MagentoBundle/Resources/config/importexport.yml
+++ b/src/OroCRM/Bundle/MagentoBundle/Resources/config/importexport.yml
@@ -31,6 +31,7 @@ parameters:
orocrm_magento.importexport.denormalizer.order_item.class: OroCRM\Bundle\MagentoBundle\ImportExport\Serializer\OrderItemCompositeDenormalizer
# strategies
+ orocrm_magento.import_strategy.customer.base_strategy.class: OroCRM\Bundle\MagentoBundle\ImportExport\Strategy\BaseStrategy
orocrm_magento.import_strategy.customer.add_or_update.class: OroCRM\Bundle\MagentoBundle\ImportExport\Strategy\CustomerStrategy
orocrm_magento.import_strategy.region.add_or_update.class: OroCRM\Bundle\MagentoBundle\ImportExport\Strategy\RegionStrategy
orocrm_magento.import_strategy.cart.add_or_update.class: OroCRM\Bundle\MagentoBundle\ImportExport\Strategy\CartStrategy
@@ -161,34 +162,36 @@ services:
- { name: oro_importexport.normalizer }
# Strategies
- orocrm_magento.import.strategy.customer.add_or_update:
- class: %orocrm_magento.import_strategy.customer.add_or_update.class%
+ orocrm_magento.import.strategy.base_strategy:
+ class: %orocrm_magento.import_strategy.customer.base_strategy.class%
+ abstract: true
arguments:
- @oro_importexport.strategy.import.helper
+ - @doctrine
+
+ orocrm_magento.import.strategy.customer.add_or_update:
+ class: %orocrm_magento.import_strategy.customer.add_or_update.class%
+ parent: orocrm_magento.import.strategy.base_strategy
orocrm_magento.import.strategy.region.add_or_update:
class: %orocrm_magento.import_strategy.region.add_or_update.class%
- arguments:
- - @oro_importexport.strategy.import.helper
+ parent: orocrm_magento.import.strategy.base_strategy
orocrm_magento.import.strategy.store:
class: %orocrm_magento.import_strategy.store.class%
- arguments:
- - @oro_importexport.strategy.import.helper
+ parent: orocrm_magento.import.strategy.base_strategy
orocrm_magento.import.strategy.cart.add_or_update:
class: %orocrm_magento.import_strategy.cart.add_or_update.class%
- arguments:
- - @oro_importexport.strategy.import.helper
- arguments:
- - @oro_importexport.strategy.import.helper
- - @orocrm_magento.import.strategy.store
+ parent: orocrm_magento.import.strategy.base_strategy
+ calls:
+ - [setStoreStrategy, [@orocrm_magento.import.strategy.store]]
orocrm_magento.import.strategy.order.add_or_update:
class: %orocrm_magento.import_strategy.order.add_or_update.class%
- arguments:
- - @oro_importexport.strategy.import.helper
- - @orocrm_magento.import.strategy.store
+ parent: orocrm_magento.import.strategy.base_strategy
+ calls:
+ - [setStoreStrategy, [@orocrm_magento.import.strategy.store]]
# Processors
orocrm_magento.importexport.processor.import_customer:
diff --git a/src/OroCRM/Bundle/MagentoBundle/Resources/config/oro/address_format.yml b/src/OroCRM/Bundle/MagentoBundle/Resources/config/oro/address_format.yml
new file mode 100644
index 00000000000..67ac19365cf
--- /dev/null
+++ b/src/OroCRM/Bundle/MagentoBundle/Resources/config/oro/address_format.yml
@@ -0,0 +1,110 @@
+AS:
+ format: '%NAME%\n%ORGANIZATION%\n%STREET%\n%CITY% %REGION% %COUNTRY% %postal_code%'
+ require: [street, city, region, postal_code]
+ zip_name_type: zip
+ region_name_type: region
+AX:
+ format: '%organization%\n%name%\n%street%\nAX-%postal_code% %city%\n%country%\nÃ…LAND'
+ require: [street, city, postal_code]
+ postprefix: AX-
+BM:
+ format: '%name%\n%organization%\n%street%\n%city% %postal_code%\n%country%'
+CC:
+ format: '%organization%\n%name%\n%street%\n%CITY% %REGION% %COUNTRY% %postal_code%'
+CK:
+ format: '%name%\n%organization%\n%street%\n%city% %postal_code%\n%country%'
+CX:
+ format: '%organization%\n%name%\n%street%\n%CITY% %REGION% %COUNTRY% %postal_code%'
+FK:
+ format: '%name%\n%organization%\n%street%\n%CITY%\n%COUNTRY%\n%POSTAL_CODE%'
+ require: [street, city, postal_code]
+FO:
+ format: '%name%\n%organization%\n%street%\nFO%postal_code% %city%\n%country%'
+ postprefix: FO
+GF:
+ format: '%organization%\n%name%\n%STREET%\n%postal_code% %CITY%\n%COUNTRY%'
+ require: [street, city, postal_code]
+GI:
+ format: '%name%\n%organization%\n%street%\n%country%'
+ require: [street]
+GP:
+ format: '%organization%\n%name%\n%STREET%\n%postal_code% %CITY%\n%COUNTRY%'
+ require: [street, city, postal_code]
+GS:
+ format: '%name%\n%organization%\n%street%\n%CITY%\n%COUNTRY%\n%POSTAL_CODE%'
+ require: [street, city, postal_code]
+GU:
+ format: '%NAME%\n%ORGANIZATION%\n%STREET%\n%CITY% %REGION% %COUNTRY% %postal_code%'
+ require: [street, city, region, postal_code]
+ zip_name_type: zip
+ region_name_type: region
+HK:
+ format: '%REGION%\n%street%\n%organization%\n%name%'
+ latin_format: '%name%\n%organization%\n%street%\n%REGION%\n%COUNTRY%'
+ require: [street, region]
+ region_name_type: area
+ format_charset: Big5
+HM:
+ format: '%organization%\n%name%\n%street%\n%CITY% %REGION% %COUNTRY% %postal_code%'
+IO:
+ format: '%name%\n%organization%\n%street%\n%CITY%\n%COUNTRY%\n%POSTAL_CODE%'
+ require: [street, city, postal_code]
+KY:
+ format: '%name%\n%organization%\n%street%\n%region%\n%country%'
+ require: [street, region]
+ region_name_type: island
+MC:
+ format: '%name%\n%organization%\n%street%\nMC-%postal_code% %city%\n%country%'
+ postprefix: MC-
+MP:
+ format: '%NAME%\n%ORGANIZATION%\n%STREET%\n%CITY% %COUNTRY% %REGION% %postal_code%'
+ require: [street, city, region, postal_code]
+ zip_name_type: zip
+ region_name_type: region
+MQ:
+ format: '%organization%\n%name%\n%STREET%\n%postal_code% %CITY%\n%COUNTRY%'
+ require: [street, city, postal_code]
+NC:
+ format: '%organization%\n%name%\n%STREET%\n%postal_code% %CITY%\n%COUNTRY%'
+ require: [street, city, postal_code]
+NF:
+ format: '%organization%\n%name%\n%street%\n%CITY% %REGION% %postal_code%'
+PF:
+ format: '%name%\n%organization%\n%street%\n%postal_code% %CITY% %REGION%\n%COUNTRY%'
+ require: [street, city, region, postal_code]
+ region_name_type: island
+PM:
+ format: '%organization%\n%name%\n%STREET%\n%postal_code% %CITY%\n%COUNTRY%'
+ require: [street, city, postal_code]
+PN:
+ format: '%name%\n%organization%\n%street%\n%CITY%\n%COUNTRY%\n%POSTAL_CODE%'
+ require: [street, city, postal_code]
+PR:
+ format: '%NAME%\n%ORGANIZATION%\n%STREET%\n%CITY% PR %postal_code%\n%COUNTRY%'
+ require: [street, city, postal_code]
+ zip_name_type: zip
+ postprefix: PR
+RE:
+ format: '%organization%\n%name%\n%STREET%\n%postal_code% %CITY%\n%COUNTRY%'
+ require: [street, city, postal_code]
+SJ:
+ format: '%name%\n%organization%\n%street%\n%postal_code% %city%\n%country%'
+ require: [street, city, postal_code]
+TC:
+ format: '%name%\n%organization%\n%street%\n%CITY%\n%COUNTRY%\n%POSTAL_CODE%'
+ require: [street, city, postal_code]
+VA:
+ format: '%name%\n%organization%\n%street%\n%postal_code% %city%\n%country%'
+VG:
+ require: [street]
+VI:
+ format: '%NAME%\n%ORGANIZATION%\n%STREET%\n%CITY% %REGION% %COUNTRY% %postal_code%'
+ require: [street, city, region, postal_code]
+ zip_name_type: zip
+ region_name_type: region
+WF:
+ format: '%organization%\n%name%\n%STREET%\n%postal_code% %CITY%\n%COUNTRY%'
+ require: [street, city, postal_code]
+YT:
+ format: '%organization%\n%name%\n%STREET%\n%postal_code% %CITY%\n%COUNTRY%'
+ require: [street, city, postal_code]
diff --git a/src/OroCRM/Bundle/MagentoBundle/Resources/config/oro/currency_data.yml b/src/OroCRM/Bundle/MagentoBundle/Resources/config/oro/currency_data.yml
new file mode 100644
index 00000000000..ba8d00d12a5
--- /dev/null
+++ b/src/OroCRM/Bundle/MagentoBundle/Resources/config/oro/currency_data.yml
@@ -0,0 +1,16 @@
+ANG:
+ symbol: ANG
+AWG:
+ symbol: Afl.
+BMD:
+ symbol: $
+FKP:
+ symbol: FKP
+GIP:
+ symbol: GIP
+HKD:
+ symbol: $
+KYD:
+ symbol: KYD
+XPF:
+ symbol: FCFP
diff --git a/src/OroCRM/Bundle/MagentoBundle/Resources/config/oro/locale_data.yml b/src/OroCRM/Bundle/MagentoBundle/Resources/config/oro/locale_data.yml
new file mode 100644
index 00000000000..60ff04cc0ba
--- /dev/null
+++ b/src/OroCRM/Bundle/MagentoBundle/Resources/config/oro/locale_data.yml
@@ -0,0 +1,166 @@
+AI:
+ currency_code: XCD
+ phone_prefix: +1-264
+ default_locale: en
+AS:
+ currency_code: USD
+ phone_prefix: +1-684
+ default_locale: en_AS
+AW:
+ currency_code: AWG
+ phone_prefix: '297'
+ default_locale: nl_AW
+AX:
+ currency_code: EUR
+ phone_prefix: +358-18
+ default_locale: sv_AX
+BM:
+ currency_code: BMD
+ phone_prefix: +1-441
+ default_locale: en_BM
+CC:
+ currency_code: AUD
+ phone_prefix: '61'
+ default_locale: ms
+CK:
+ currency_code: NZD
+ phone_prefix: '682'
+ default_locale: en
+CX:
+ currency_code: AUD
+ phone_prefix: '61'
+ default_locale: en
+EH:
+ currency_code: MAD
+ phone_prefix: '212'
+ default_locale: ar
+FK:
+ currency_code: FKP
+ phone_prefix: '500'
+ default_locale: en
+FO:
+ currency_code: DKK
+ phone_prefix: '298'
+ default_locale: fo
+GF:
+ currency_code: EUR
+ phone_prefix: '594'
+ default_locale: fr_GF
+GI:
+ currency_code: GIP
+ phone_prefix: '350'
+ default_locale: en_GI
+GP:
+ currency_code: EUR
+ phone_prefix: '590'
+ default_locale: fr_GP
+GS:
+ currency_code: GBP
+ default_locale: en
+GU:
+ currency_code: USD
+ phone_prefix: +1-671
+ default_locale: en_GU
+HK:
+ currency_code: HKD
+ phone_prefix: '852'
+ default_locale: zh_HK
+IO:
+ currency_code: USD
+ phone_prefix: '246'
+ default_locale: en
+KY:
+ currency_code: KYD
+ phone_prefix: +1-345
+ default_locale: en_KY
+LC:
+ currency_code: XCD
+ phone_prefix: +1-758
+ default_locale: en_LC
+MC:
+ currency_code: EUR
+ phone_prefix: '377'
+ default_locale: fr_MC
+MP:
+ currency_code: USD
+ phone_prefix: +1-670
+ default_locale: fil
+MQ:
+ currency_code: EUR
+ phone_prefix: '596'
+ default_locale: fr_MQ
+MS:
+ currency_code: XCD
+ phone_prefix: +1-664
+ default_locale: en
+NC:
+ currency_code: XPF
+ phone_prefix: '687'
+ default_locale: fr_NC
+NF:
+ currency_code: AUD
+ phone_prefix: '672'
+ default_locale: en
+NU:
+ currency_code: NZD
+ phone_prefix: '683'
+ default_locale: en
+PF:
+ currency_code: XPF
+ phone_prefix: '689'
+ default_locale: fr_PF
+PM:
+ currency_code: EUR
+ phone_prefix: '508'
+ default_locale: fr
+PN:
+ currency_code: NZD
+ phone_prefix: '870'
+ default_locale: en
+PR:
+ currency_code: USD
+ phone_prefix: +1-787
+ default_locale: en_PR
+RE:
+ currency_code: EUR
+ phone_prefix: '262'
+ default_locale: fr_RE
+SJ:
+ currency_code: NOK
+ phone_prefix: '47'
+ default_locale: no
+TC:
+ currency_code: USD
+ phone_prefix: +1-649
+ default_locale: en_TC
+TF:
+ currency_code: EUR
+ default_locale: fr
+TK:
+ currency_code: NZD
+ phone_prefix: '690'
+ default_locale: en
+VA:
+ currency_code: EUR
+ phone_prefix: '379'
+ default_locale: it
+VG:
+ currency_code: USD
+ phone_prefix: +1-284
+ default_locale: en_VG
+VI:
+ currency_code: USD
+ phone_prefix: +1-340
+ default_locale: en_VI
+WF:
+ currency_code: XPF
+ phone_prefix: '681'
+ default_locale: fr
+YT:
+ currency_code: EUR
+ phone_prefix: '262'
+ default_locale: fr_YT
+AN:
+ currency_code: ANG
+ phone_prefix: '599'
+ default_locale: nl
diff --git a/src/OroCRM/Bundle/MagentoBundle/Resources/config/workflow.yml b/src/OroCRM/Bundle/MagentoBundle/Resources/config/workflow.yml
index cc2ad6d524c..40008c88e0e 100644
--- a/src/OroCRM/Bundle/MagentoBundle/Resources/config/workflow.yml
+++ b/src/OroCRM/Bundle/MagentoBundle/Resources/config/workflow.yml
@@ -166,7 +166,7 @@ workflows:
constraints:
- NotBlank: ~
call_duration:
- form_type: time
+ form_type: oro_time_interval
options:
required: false
widget: single_text
@@ -200,13 +200,10 @@ workflows:
- @not_empty: $cart.customer
- @not_empty: $cart.customer.contact
parameters: [$contact, $cart.customer.contact]
- - @create_object:
- class: '\DateTime'
+ - @create_datetime:
attribute: $call_date
- - @create_object:
- class: '\DateTime'
- arguments:
- - '00:00:00'
+ - @create_datetime:
+ time: '00:00:00'
attribute: $call_duration
send_email:
label: 'Send email'
@@ -475,10 +472,10 @@ workflows:
class: OroCRM\Bundle\MagentoBundle\Entity\CartStatus
identifier: 'converted_to_opportunity'
attribute: $cart.status
- - @find_entity: # set status "In progress" to opportunity
- class: OroCRM\Bundle\MagentoBundle\Entity\CartStatus
- identifier: 'in_progress'
- attribute: $.result.opportunity_status
+ - @find_entity:
+ class: OroCRM\Bundle\SalesBundle\Entity\OpportunityStatus
+ identifier: 'in_progress'
+ attribute: $.result.opportunity_status
- @create_entity: # create an opportunity
class: OroCRM\Bundle\SalesBundle\Entity\Opportunity
attribute: $cart.opportunity
@@ -680,7 +677,7 @@ workflows:
constraints:
- NotBlank: ~
call_duration:
- form_type: time
+ form_type: oro_time_interval
options:
required: false
widget: single_text
@@ -743,13 +740,10 @@ workflows:
- @not_empty: $order.cart.customer.contact
parameters: [$contact, $order.cart.customer.contact]
- - @create_object:
- class: '\DateTime'
+ - @create_datetime:
attribute: $call_date
- - @create_object:
- class: '\DateTime'
- arguments:
- - '00:00:00'
+ - @create_datetime:
+ time: '00:00:00'
attribute: $call_duration
send_email:
label: 'Send email'
diff --git a/src/OroCRM/Bundle/MagentoBundle/Resources/translations/entities.en.yml b/src/OroCRM/Bundle/MagentoBundle/Resources/translations/entities.en.yml
new file mode 100644
index 00000000000..b1ca0754076
--- /dev/null
+++ b/src/OroCRM/Bundle/MagentoBundle/Resources/translations/entities.en.yml
@@ -0,0 +1,46 @@
+country:
+ AI: Anguilla
+ AN: 'Netherlands Antilles'
+ AQ: Antarctica
+ AS: 'American Samoa'
+ AW: Aruba
+ AX: 'Aland Islands'
+ BM: Bermuda
+ BV: 'Bouvet Island'
+ CC: 'Cocos Islands'
+ CK: 'Cook Islands'
+ CX: 'Christmas Island'
+ EH: 'Western Sahara'
+ FK: 'Falkland Islands'
+ FO: 'Faroe Islands'
+ GF: 'French Guiana'
+ GI: Gibraltar
+ GP: Guadeloupe
+ GS: 'South Georgia and the South Sandwich Islands'
+ GU: Guam
+ HK: 'Hong Kong'
+ HM: 'Heard Island and McDonald Islands'
+ IO: 'British Indian Ocean Territory'
+ KY: 'Cayman Islands'
+ LC: 'Saint Lucia'
+ MC: Monaco
+ MP: 'Northern Mariana Islands'
+ MQ: Martinique
+ MS: Montserrat
+ NC: 'New Caledonia'
+ NF: 'Norfolk Island'
+ NU: Niue
+ PF: 'French Polynesia'
+ PM: 'Saint Pierre and Miquelon'
+ PN: Pitcairn
+ PR: 'Puerto Rico'
+ RE: Reunion
+ SJ: 'Svalbard and Jan Mayen'
+ TC: 'Turks and Caicos Islands'
+ TF: 'French Southern Territories'
+ TK: Tokelau
+ VA: Vatican
+ VG: 'British Virgin Islands'
+ VI: 'U.S. Virgin Islands'
+ WF: 'Wallis and Futuna'
+ YT: Mayotte
diff --git a/src/OroCRM/Bundle/ReportBundle/Tests/Functional/ControllersCrmTest.php b/src/OroCRM/Bundle/ReportBundle/Tests/Functional/ControllersCrmTest.php
index 10950b0ac07..679bb2bd40f 100644
--- a/src/OroCRM/Bundle/ReportBundle/Tests/Functional/ControllersCrmTest.php
+++ b/src/OroCRM/Bundle/ReportBundle/Tests/Functional/ControllersCrmTest.php
@@ -1,6 +1,6 @@
markTestSkipped("Skipped by BAP-2946");
+ }
+ /**
* Data provider for SOAP API tests
*
* @return array
diff --git a/src/OroCRM/Bundle/SalesBundle/Controller/Api/Rest/SalesFunnelController.php b/src/OroCRM/Bundle/SalesBundle/Controller/Api/Rest/SalesFunnelController.php
new file mode 100644
index 00000000000..0e56e72f357
--- /dev/null
+++ b/src/OroCRM/Bundle/SalesBundle/Controller/Api/Rest/SalesFunnelController.php
@@ -0,0 +1,154 @@
+getRequest()->get('page', 1);
+ $limit = (int)$this->getRequest()->get('limit', self::ITEMS_PER_PAGE);
+
+ return $this->handleGetListRequest($page, $limit);
+ }
+
+ /**
+ * REST GET item
+ *
+ * @param string $id
+ *
+ * @ApiDoc(
+ * description="Get opportunity",
+ * resource=true
+ * )
+ * @AclAncestor("orocrm_sales_salesfunnel_view")
+ * @return Response
+ */
+ public function getAction($id)
+ {
+ return $this->handleGetRequest($id);
+ }
+
+ /**
+ * REST PUT
+ *
+ * @param int $id
+ *
+ * @ApiDoc(
+ * description="Update sales funnel",
+ * resource=true
+ * )
+ * @AclAncestor("orocrm_sales_salesfunnel_update")
+ * @return Response
+ */
+ public function putAction($id)
+ {
+ return $this->handleUpdateRequest($id);
+ }
+
+ /**
+ * Create new lead
+ *
+ * @ApiDoc(
+ * description="Create new sales funnel",
+ * resource=true
+ * )
+ * @AclAncestor("orocrm_sales_salesfunnel_create")
+ */
+ public function postAction()
+ {
+ return $this->handleCreateRequest();
+ }
+
+ /**
+ * REST DELETE
+ *
+ * @param int $id
+ *
+ * @ApiDoc(
+ * description="Delete sales funnel",
+ * resource=true
+ * )
+ * @Acl(
+ * id="orocrm_sales_salesfunnel_delete",
+ * type="entity",
+ * permission="DELETE",
+ * class="OroCRMSalesBundle:SalesFunnel"
+ * )
+ * @return Response
+ */
+ public function deleteAction($id)
+ {
+ return $this->handleDeleteRequest($id);
+ }
+
+ /**
+ * Get entity Manager
+ *
+ * @return ApiEntityManager
+ */
+ public function getManager()
+ {
+ return $this->get('orocrm_sales.salesfunnel.manager.api');
+ }
+
+ /**
+ * @return FormInterface
+ */
+ public function getForm()
+ {
+ return $this->get('orocrm_sales.salesfunnel.form.api');
+ }
+
+ /**
+ * @return ApiFormHandler
+ */
+ public function getFormHandler()
+ {
+ return $this->get('orocrm_sales.salesfunnel.form.handler.api');
+ }
+}
diff --git a/src/OroCRM/Bundle/SalesBundle/Controller/Dashboard/DashboardController.php b/src/OroCRM/Bundle/SalesBundle/Controller/Dashboard/DashboardController.php
index 01cb08f0c3a..16f1fc28dbf 100644
--- a/src/OroCRM/Bundle/SalesBundle/Controller/Dashboard/DashboardController.php
+++ b/src/OroCRM/Bundle/SalesBundle/Controller/Dashboard/DashboardController.php
@@ -12,7 +12,7 @@ class DashboardController extends Controller
/**
* @Route(
* "/opportunities_by_lead_source/chart/{widget}",
- * name="oro_sales_dashboard_opportunities_by_lead_source_chart",
+ * name="orocrm_sales_dashboard_opportunities_by_lead_source_chart",
* requirements={"widget"="[\w-]+"}
* )
* @Template("OroDashboardBundle:Dashboard:pieChart.html.twig")
diff --git a/src/OroCRM/Bundle/SalesBundle/Controller/LeadController.php b/src/OroCRM/Bundle/SalesBundle/Controller/LeadController.php
index 69d13dab725..713f6920f96 100644
--- a/src/OroCRM/Bundle/SalesBundle/Controller/LeadController.php
+++ b/src/OroCRM/Bundle/SalesBundle/Controller/LeadController.php
@@ -71,10 +71,7 @@ public function addressBookAction(Lead $lead)
*/
public function createAction()
{
- $lead = new Lead();
- $defaultStatus = $this->getDoctrine()->getManager()->find('OroCRMSalesBundle:LeadStatus', 'new');
- $lead->setStatus($defaultStatus);
-
+ $lead = new Lead();
return $this->update($lead);
}
diff --git a/src/OroCRM/Bundle/SalesBundle/Controller/OpportunityController.php b/src/OroCRM/Bundle/SalesBundle/Controller/OpportunityController.php
index faa9b020053..21c816a2f70 100644
--- a/src/OroCRM/Bundle/SalesBundle/Controller/OpportunityController.php
+++ b/src/OroCRM/Bundle/SalesBundle/Controller/OpportunityController.php
@@ -59,9 +59,6 @@ public function infoAction(Opportunity $entity)
public function createAction()
{
$entity = new Opportunity();
- $defaultStatus = $this->getDoctrine()->getManager()->find('OroCRMSalesBundle:OpportunityStatus', 'in_progress');
- $entity->setStatus($defaultStatus);
-
return $this->update($entity);
}
diff --git a/src/OroCRM/Bundle/SalesBundle/Controller/SalesFunnelController.php b/src/OroCRM/Bundle/SalesBundle/Controller/SalesFunnelController.php
new file mode 100644
index 00000000000..a340141e03d
--- /dev/null
+++ b/src/OroCRM/Bundle/SalesBundle/Controller/SalesFunnelController.php
@@ -0,0 +1,121 @@
+ $this->container->getParameter('orocrm_sales.salesfunnel.entity.class')
+ );
+ }
+
+ /**
+ * @Route("/view/{id}", name="orocrm_sales_salesfunnel_view", requirements={"id"="\d+"})
+ * @Template
+ * @Acl(
+ * id="orocrm_sales_salesfunnel_view",
+ * type="entity",
+ * permission="VIEW",
+ * class="OroCRMSalesBundle:SalesFunnel"
+ * )
+ */
+ public function viewAction(SalesFunnel $entity)
+ {
+ return array(
+ 'entity' => $entity,
+ );
+ }
+
+ /**
+ * @Route("/info/{id}", name="orocrm_sales_salesfunnel_info", requirements={"id"="\d+"})
+ * @Template
+ * @AclAncestor("orocrm_sales_salesfunnel_view")
+ */
+ public function infoAction(SalesFunnel $entity)
+ {
+ return array(
+ 'entity' => $entity
+ );
+ }
+
+ /**
+ * @Route("/create", name="orocrm_sales_salesfunnel_create")
+ * @Template("OroCRMSalesBundle:SalesFunnel:update.html.twig")
+ * @Acl(
+ * id="orocrm_sales_salesfunnel_create",
+ * type="entity",
+ * permission="CREATE",
+ * class="OroCRMSalesBundle:SalesFunnel"
+ * )
+ */
+ public function createAction()
+ {
+ $entity = new SalesFunnel();
+ return $this->update($entity);
+ }
+
+ /**
+ * @Route("/update/{id}", name="orocrm_sales_salesfunnel_update", requirements={"id"="\d+"}, defaults={"id"=0})
+ * @Template
+ * @Acl(
+ * id="orocrm_sales_salesfunnel_update",
+ * type="entity",
+ * permission="EDIT",
+ * class="OroCRMSalesBundle:SalesFunnel"
+ * )
+ */
+ public function updateAction(SalesFunnel $entity)
+ {
+ return $this->update($entity);
+ }
+
+ /**
+ * @param SalesFunnel $entity
+ * @return array
+ */
+ protected function update(SalesFunnel $entity)
+ {
+ if ($this->get('orocrm_sales.salesfunnel.form.handler')->process($entity)) {
+ $this->get('session')->getFlashBag()->add(
+ 'success',
+ $this->get('translator')->trans('orocrm.sales.controller.sales_funnel.saved.message')
+ );
+
+ return $this->get('oro_ui.router')->redirectAfterSave(
+ array('route' => 'orocrm_sales_salesfunnel_update', 'parameters' => array('id' => $entity->getId())),
+ array('route' => 'orocrm_sales_salesfunnel_view', 'parameters' => array('id' => $entity->getId())),
+ $entity
+ );
+ }
+
+ return array(
+ 'entity' => $entity,
+ 'form' => $this->get('orocrm_sales.salesfunnel.form')->createView(),
+ );
+ }
+}
diff --git a/src/OroCRM/Bundle/SalesBundle/Entity/Lead.php b/src/OroCRM/Bundle/SalesBundle/Entity/Lead.php
index 96b584d2382..16560fae9fa 100644
--- a/src/OroCRM/Bundle/SalesBundle/Entity/Lead.php
+++ b/src/OroCRM/Bundle/SalesBundle/Entity/Lead.php
@@ -2,6 +2,7 @@
namespace OroCRM\Bundle\SalesBundle\Entity;
+use Doctrine\ORM\Event\LifecycleEventArgs;
use Doctrine\ORM\Mapping as ORM;
use Doctrine\Common\Collections\ArrayCollection;
@@ -29,6 +30,9 @@
* routeName="orocrm_sales_lead_index",
* routeView="orocrm_sales_lead_view",
* defaultValues={
+ * "entity"={
+ * "icon"="icon-phone"
+ * },
* "ownership"={
* "owner_type"="USER",
* "owner_field_name"="owner",
@@ -37,6 +41,9 @@
* "security"={
* "type"="ACL",
* "group_name"=""
+ * },
+ * "workflow"={
+ * "active_workflow"="b2b_flow_lead"
* }
* }
* )
@@ -798,4 +805,15 @@ public function getWorkflowStep()
{
return $this->workflowStep;
}
+
+ /**
+ * @ORM\PrePersist
+ */
+ public function prePersist(LifecycleEventArgs $eventArgs)
+ {
+ $em = $eventArgs->getEntityManager();
+ /** @var LeadStatus $defaultStatus */
+ $defaultStatus = $em->getReference('OroCRMSalesBundle:LeadStatus', 'new');
+ $this->setStatus($defaultStatus);
+ }
}
diff --git a/src/OroCRM/Bundle/SalesBundle/Entity/Opportunity.php b/src/OroCRM/Bundle/SalesBundle/Entity/Opportunity.php
index 10a4e2359ab..10f810b2bab 100644
--- a/src/OroCRM/Bundle/SalesBundle/Entity/Opportunity.php
+++ b/src/OroCRM/Bundle/SalesBundle/Entity/Opportunity.php
@@ -2,6 +2,7 @@
namespace OroCRM\Bundle\SalesBundle\Entity;
+use Doctrine\ORM\Event\LifecycleEventArgs;
use Doctrine\ORM\Mapping as ORM;
use Oro\Bundle\DataAuditBundle\Metadata\Annotation as Oro;
@@ -23,6 +24,9 @@
* routeName="orocrm_sales_opportunity_index",
* routeView="orocrm_sales_opportunity_view",
* defaultValues={
+ * "entity"={
+ * "icon"="icon-usd"
+ * },
* "ownership"={
* "owner_type"="USER",
* "owner_field_name"="owner",
@@ -31,6 +35,9 @@
* "security"={
* "type"="ACL",
* "group_name"=""
+ * },
+ * "workflow"={
+ * "active_workflow"="b2b_flow_sales"
* }
* }
* )
@@ -498,16 +505,16 @@ public function __toString()
/**
* @ORM\PrePersist
*/
- public function prePersist()
+ public function beforeSave()
{
$this->createdAt = new \DateTime('now', new \DateTimeZone('UTC'));
- $this->preUpdate();
+ $this->beforeUpdate();
}
/**
* @ORM\PreUpdate
*/
- public function preUpdate()
+ public function beforeUpdate()
{
$this->updatedAt = new \DateTime('now', new \DateTimeZone('UTC'));
}
@@ -548,4 +555,15 @@ public function setNotes($notes)
$this->notes = $notes;
return $this;
}
+
+ /**
+ * @ORM\PrePersist
+ */
+ public function prePersist(LifecycleEventArgs $eventArgs)
+ {
+ $em = $eventArgs->getEntityManager();
+ /** @var LeadStatus $defaultStatus */
+ $defaultStatus = $em->getReference('OroCRMSalesBundle:OpportunityStatus', 'in_progress');
+ $this->setStatus($defaultStatus);
+ }
}
diff --git a/src/OroCRM/Bundle/SalesBundle/Entity/SalesFunnel.php b/src/OroCRM/Bundle/SalesBundle/Entity/SalesFunnel.php
new file mode 100644
index 00000000000..045662d0f2d
--- /dev/null
+++ b/src/OroCRM/Bundle/SalesBundle/Entity/SalesFunnel.php
@@ -0,0 +1,320 @@
+id;
+ }
+
+ /**
+ * @return string
+ */
+ public function getName()
+ {
+ return $this->name;
+ }
+
+ /**
+ * @param string $name
+ * @return SalesFunnel
+ */
+ public function setName($name)
+ {
+ $this->name = $name;
+
+ return $this;
+ }
+
+ /**
+ * @param \DateTime $createdAt
+ * @return SalesFunnel
+ */
+ public function setCreatedAt($createdAt)
+ {
+ $this->createdAt = $createdAt;
+
+ return $this;
+ }
+
+ /**
+ * @return \DateTime
+ */
+ public function getCreatedAt()
+ {
+ return $this->createdAt;
+ }
+
+ /**
+ * @param \OroCRM\Bundle\SalesBundle\Entity\Lead $lead
+ * @return SalesFunnel
+ */
+ public function setLead($lead)
+ {
+ $this->lead = $lead;
+
+ return $this;
+ }
+
+ /**
+ * @return \OroCRM\Bundle\SalesBundle\Entity\Lead
+ */
+ public function getLead()
+ {
+ return $this->lead;
+ }
+
+ /**
+ * @param \OroCRM\Bundle\SalesBundle\Entity\Opportunity $opportunity
+ * @return SalesFunnel
+ */
+ public function setOpportunity($opportunity)
+ {
+ $this->opportunity = $opportunity;
+
+ return $this;
+ }
+
+ /**
+ * @return \OroCRM\Bundle\SalesBundle\Entity\Opportunity
+ */
+ public function getOpportunity()
+ {
+ return $this->opportunity;
+ }
+
+ /**
+ * @param \Oro\Bundle\UserBundle\Entity\User $owner
+ * @return SalesFunnel
+ */
+ public function setOwner($owner)
+ {
+ $this->owner = $owner;
+
+ return $this;
+ }
+
+ /**
+ * @return \Oro\Bundle\UserBundle\Entity\User
+ */
+ public function getOwner()
+ {
+ return $this->owner;
+ }
+
+ /**
+ * @param \DateTime $startDate
+ * @return SalesFunnel
+ */
+ public function setStartDate($startDate)
+ {
+ $this->startDate = $startDate;
+
+ return $this;
+ }
+
+ /**
+ * @return \DateTime
+ */
+ public function getStartDate()
+ {
+ return $this->startDate;
+ }
+
+ /**
+ * @param \DateTime $updatedAt
+ * @return SalesFunnel
+ */
+ public function setUpdatedAt($updatedAt)
+ {
+ $this->updatedAt = $updatedAt;
+
+ return $this;
+ }
+
+ /**
+ * @return \DateTime
+ */
+ public function getUpdatedAt()
+ {
+ return $this->updatedAt;
+ }
+
+ /**
+ * @param WorkflowItem $workflowItem
+ * @return SalesFunnel
+ */
+ public function setWorkflowItem($workflowItem)
+ {
+ $this->workflowItem = $workflowItem;
+
+ return $this;
+ }
+
+ /**
+ * @return WorkflowItem
+ */
+ public function getWorkflowItem()
+ {
+ return $this->workflowItem;
+ }
+
+ /**
+ * @param WorkflowItem $workflowStep
+ * @return SalesFunnel
+ */
+ public function setWorkflowStep($workflowStep)
+ {
+ $this->workflowStep = $workflowStep;
+
+ return $this;
+ }
+
+ /**
+ * @return WorkflowStep
+ */
+ public function getWorkflowStep()
+ {
+ return $this->workflowStep;
+ }
+
+ /**
+ * Pre persist event listener
+ *
+ * @ORM\PrePersist
+ */
+ public function beforeSave()
+ {
+ $this->createdAt = new \DateTime('now', new \DateTimeZone('UTC'));
+ }
+
+ /**
+ * Pre update event handler
+ * @ORM\PreUpdate
+ */
+ public function beforeUpdate()
+ {
+ $this->updatedAt = new \DateTime('now', new \DateTimeZone('UTC'));
+ }
+}
diff --git a/src/OroCRM/Bundle/SalesBundle/Form/Handler/SalesFunnelHandler.php b/src/OroCRM/Bundle/SalesBundle/Form/Handler/SalesFunnelHandler.php
new file mode 100644
index 00000000000..4abe7430a95
--- /dev/null
+++ b/src/OroCRM/Bundle/SalesBundle/Form/Handler/SalesFunnelHandler.php
@@ -0,0 +1,72 @@
+form = $form;
+ $this->request = $request;
+ $this->manager = $manager;
+ }
+
+ /**
+ * Process form
+ *
+ * @param SalesFunnel $entity
+ * @return bool True on successful processing, false otherwise
+ */
+ public function process(SalesFunnel $entity)
+ {
+ $this->form->setData($entity);
+
+ if (in_array($this->request->getMethod(), array('POST', 'PUT'))) {
+ $this->form->submit($this->request);
+
+ if ($this->form->isValid()) {
+ $this->onSuccess($entity);
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * "Success" form handler
+ *
+ * @param SalesFunnel $entity
+ */
+ protected function onSuccess(SalesFunnel $entity)
+ {
+ $this->manager->persist($entity);
+ $this->manager->flush();
+ }
+}
diff --git a/src/OroCRM/Bundle/SalesBundle/Form/Type/LeadSelectType.php b/src/OroCRM/Bundle/SalesBundle/Form/Type/LeadSelectType.php
new file mode 100644
index 00000000000..2628cb2d095
--- /dev/null
+++ b/src/OroCRM/Bundle/SalesBundle/Form/Type/LeadSelectType.php
@@ -0,0 +1,33 @@
+setDefaults(
+ array(
+ 'configs' => array(
+ 'placeholder' => 'orocrm.sales.form.choose_lead'
+ ),
+ 'autocomplete_alias' => 'leads'
+ )
+ );
+ }
+
+ public function getParent()
+ {
+ return 'oro_jqueryselect2_hidden';
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getName()
+ {
+ return 'orocrm_sales_lead_select';
+ }
+}
diff --git a/src/OroCRM/Bundle/SalesBundle/Form/Type/LeadType.php b/src/OroCRM/Bundle/SalesBundle/Form/Type/LeadType.php
index a39562e82e0..00f49da5d2c 100644
--- a/src/OroCRM/Bundle/SalesBundle/Form/Type/LeadType.php
+++ b/src/OroCRM/Bundle/SalesBundle/Form/Type/LeadType.php
@@ -2,7 +2,6 @@
namespace OroCRM\Bundle\SalesBundle\Form\Type;
-use Oro\Bundle\EntityConfigBundle\Config\Id\FieldConfigId;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
diff --git a/src/OroCRM/Bundle/SalesBundle/Form/Type/OpportunitySelectType.php b/src/OroCRM/Bundle/SalesBundle/Form/Type/OpportunitySelectType.php
index bec66d3bfdc..45b449b7695 100644
--- a/src/OroCRM/Bundle/SalesBundle/Form/Type/OpportunitySelectType.php
+++ b/src/OroCRM/Bundle/SalesBundle/Form/Type/OpportunitySelectType.php
@@ -11,9 +11,7 @@ public function setDefaultOptions(OptionsResolverInterface $resolver)
$resolver->setDefaults(
array(
'configs' => array(
- 'placeholder' => 'orocrm.sales.form.choose_opportunity',
- 'result_template_twig' => 'OroCRMSalesBundle:Opportunity:Autocomplete/result.html.twig',
- 'selection_template_twig' => 'OroCRMSalesBundle:Opportunity:Autocomplete/selection.html.twig'
+ 'placeholder' => 'orocrm.sales.form.choose_opportunity'
),
'autocomplete_alias' => 'opportunities'
)
diff --git a/src/OroCRM/Bundle/SalesBundle/Form/Type/SalesFunnelApiType.php b/src/OroCRM/Bundle/SalesBundle/Form/Type/SalesFunnelApiType.php
new file mode 100644
index 00000000000..cd527d90738
--- /dev/null
+++ b/src/OroCRM/Bundle/SalesBundle/Form/Type/SalesFunnelApiType.php
@@ -0,0 +1,41 @@
+addEventSubscriber(new PatchSubscriber());
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function setDefaultOptions(OptionsResolverInterface $resolver)
+ {
+ $resolver->setDefaults(
+ array(
+ 'data_class' => 'OroCRM\Bundle\SalesBundle\Entity\SalesFunnel',
+ 'intention' => 'group',
+ 'csrf_protection' => false,
+ )
+ );
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getName()
+ {
+ return 'orocrm_sales_salesfunnel_api';
+ }
+}
diff --git a/src/OroCRM/Bundle/SalesBundle/Form/Type/SalesFunnelType.php b/src/OroCRM/Bundle/SalesBundle/Form/Type/SalesFunnelType.php
new file mode 100644
index 00000000000..683e678b6ed
--- /dev/null
+++ b/src/OroCRM/Bundle/SalesBundle/Form/Type/SalesFunnelType.php
@@ -0,0 +1,46 @@
+add('name', 'text', array('required' => true, 'label' => 'orocrm.sales.salesfunnel.name.label'))
+ ->add(
+ 'startDate',
+ 'oro_date',
+ array('required' => true, 'label' => 'orocrm.sales.salesfunnel.start_date.label')
+ );
+ }
+
+ /**
+ * @param OptionsResolverInterface $resolver
+ */
+ public function setDefaultOptions(OptionsResolverInterface $resolver)
+ {
+ $resolver->setDefaults(
+ array(
+ 'data_class' => 'OroCRM\Bundle\SalesBundle\Entity\SalesFunnel',
+ 'cascade_validation' => false,
+ )
+ );
+ }
+
+ /**
+ * @return string
+ */
+ public function getName()
+ {
+ return 'orocrm_sales_funnel';
+ }
+}
diff --git a/src/OroCRM/Bundle/SalesBundle/Resources/config/dashboard.yml b/src/OroCRM/Bundle/SalesBundle/Resources/config/dashboard.yml
index 9c5ccf7f9dc..e4f22670b1f 100644
--- a/src/OroCRM/Bundle/SalesBundle/Resources/config/dashboard.yml
+++ b/src/OroCRM/Bundle/SalesBundle/Resources/config/dashboard.yml
@@ -46,7 +46,7 @@ oro_dashboard_config:
acl: orocrm_sales_opportunity_create
opportunities_by_lead_source_chart:
label: Opportunities By Lead Source
- route: oro_sales_dashboard_opportunities_by_lead_source_chart
+ route: orocrm_sales_dashboard_opportunities_by_lead_source_chart
acl: orocrm_sales_opportunity_view
opportunities_by_state:
label: Opportunities by Status
diff --git a/src/OroCRM/Bundle/SalesBundle/Resources/config/datagrid.yml b/src/OroCRM/Bundle/SalesBundle/Resources/config/datagrid.yml
index c309df680be..15fb1d55014 100644
--- a/src/OroCRM/Bundle/SalesBundle/Resources/config/datagrid.yml
+++ b/src/OroCRM/Bundle/SalesBundle/Resources/config/datagrid.yml
@@ -3,6 +3,7 @@ datagrid:
extended_entity_name: %orocrm_sales.opportunity.class%
options:
entityHint: opportunities
+ export: true
source:
type: orm
acl_resource: orocrm_sales_opportunity_view
@@ -12,6 +13,7 @@ datagrid:
- o.name
- o.closeDate
- o.probability
+ - o.budgetAmount
- CONCAT(contact.firstName, CONCAT(' ', contact.lastName)) as contactName
- status.label as statusLabel
- step.label as stepLabel
@@ -32,13 +34,14 @@ datagrid:
closeDate:
label: orocrm.sales.opportunity.close_date.label
frontend_type: date
+ budgetAmount:
+ label: orocrm.sales.opportunity.budget_amount.label
+ frontend_type: currency
probability:
label: orocrm.sales.opportunity.probability.label
frontend_type: percent
statusLabel:
label: orocrm.sales.opportunity.status.label
- stepLabel:
- label: orocrm.sales.opportunity.b2b_flow_sales.step.label
primaryEmail:
label: orocrm.contact.email.label
properties:
@@ -63,12 +66,12 @@ datagrid:
data_name: contactName
closeDate:
data_name: o.closeDate
+ budgetAmount:
+ data_name: o.budgetAmount
probability:
data_name: o.probability
statusLabel:
data_name: status.label
- stepLabel:
- data_name: step.label
primaryEmail:
data_name: email.email
filters:
@@ -83,6 +86,9 @@ datagrid:
closeDate:
type: date
data_name: o.closeDate
+ budgetAmount:
+ type: number
+ data_name: o.budgetAmount
probability:
type: percent
data_name: o.probability
@@ -93,13 +99,6 @@ datagrid:
field_options:
class: OroCRMSalesBundle:OpportunityStatus
property: label
- stepLabel:
- type: entity
- data_name: o.workflowStep
- options:
- field_type: oro_workflow_step_select
- field_options:
- workflow_entity_class: %orocrm_sales.opportunity.class%
primaryEmail:
type: string
data_name: email.email
@@ -129,6 +128,7 @@ datagrid:
extended_entity_name: %orocrm_sales.lead.entity.class%
options:
entityHint: leads
+ export: true
source:
type: orm
acl_resource: orocrm_sales_lead_view
@@ -192,7 +192,6 @@ datagrid:
route: oro_api_delete_lead
params: [ id ]
sorters:
- multiple_sorting: true
columns:
name:
data_name: l.name
@@ -277,3 +276,318 @@ datagrid:
type: string
data_name: addressPostalCode
enabled: false
+
+ sales-funnel-grid:
+ extended_entity_name: %orocrm_sales.salesfunnel.entity.class%
+ options:
+ entityHint: sales activity
+ source:
+ type: orm
+ acl_resource: orocrm_sales_salesfunnel_view
+ query:
+ select:
+ - salesFunnel.id
+ - salesFunnel.name
+ - salesFunnel.startDate
+ - lead.name as leadName
+ - opportunity.name as opportunityName
+ - opportunity.budgetAmount as opportunityBudget
+ - opportunity.probability as opportunityProbability
+ - step.label as stepLabel
+ from:
+ - { table: %orocrm_sales.salesfunnel.entity.class%, alias: salesFunnel }
+ join:
+ left:
+ - { join: salesFunnel.workflowStep, alias: step }
+ - { join: salesFunnel.lead, alias: lead }
+ - { join: salesFunnel.opportunity, alias: opportunity }
+ columns:
+ name:
+ label: orocrm.sales.salesfunnel.name.label
+ startDate:
+ label: orocrm.sales.salesfunnel.start_date.label
+ frontend_type: date
+ leadName:
+ label: orocrm.sales.salesfunnel.lead.label
+ opportunityName:
+ label: orocrm.sales.salesfunnel.opportunity.label
+ opportunityBudget:
+ label: orocrm.sales.opportunity.budget_amount.label
+ frontend_type: currency
+ opportunityProbability:
+ label: orocrm.sales.opportunity.probability.label
+ frontend_type: percent
+ stepLabel:
+ label: orocrm.sales.salesfunnel.workflow_step.label
+ properties:
+ id: ~
+ view_link:
+ type: url
+ route: orocrm_sales_salesfunnel_view
+ params: [ id ]
+ update_link:
+ type: url
+ route: orocrm_sales_salesfunnel_update
+ params: [ id ]
+ delete_link:
+ type: url
+ route: oro_api_delete_salesfunnel
+ params: [ id ]
+ sorters:
+ columns:
+ name:
+ data_name: salesFunnel.name
+ startDate:
+ data_name: salesFunnel.startDate
+ leadName:
+ data_name: lead.name
+ opportunityName:
+ data_name: opportunity.name
+ opportunityBudget:
+ data_name: opportunity.budgetAmount
+ opportunityProbability:
+ data_name: opportunity.probability
+ stepLabel:
+ data_name: step.label
+ default:
+ startDate: %oro_datagrid.extension.orm_sorter.class%::DIRECTION_DESC
+ actions:
+ view:
+ type: navigate
+ acl_resource: orocrm_sales_salesfunnel_view
+ label: orocrm.sales.salesfunnel.datagrid.view
+ icon: user
+ link: view_link
+ rowAction: true
+ update:
+ type: navigate
+ acl_resource: orocrm_sales_salesfunnel_update
+ label: orocrm.sales.salesfunnel.datagrid.update
+ icon: edit
+ link: update_link
+ delete:
+ type: delete
+ acl_resource: orocrm_sales_salesfunnel_delete
+ label: orocrm.sales.salesfunnel.datagrid.delete
+ icon: trash
+ link: delete_link
+ filters:
+ columns:
+ name:
+ type: string
+ data_name: salesFunnel.name
+ startDate:
+ type: date
+ data_name: salesFunnel.startDate
+ leadName:
+ type: string
+ data_name: lead.name
+ opportunityName:
+ type: string
+ data_name: opportunity.name
+ opportunityBudget:
+ type: number
+ data_name: opportunity.budgetAmount
+ opportunityProbability:
+ type: percent
+ data_name: opportunity.probability
+ stepLabel:
+ type: entity
+ data_name: salesFunnel.workflowStep
+ options:
+ field_type: oro_workflow_step_select
+ field_options:
+ workflow_entity_class: %orocrm_sales.salesfunnel.entity.class%
+
+ # leads with "New" status for Sales Funnel flow
+ sales-funnel-lead-grid:
+ extended_entity_name: %orocrm_sales.lead.entity.class%
+ options:
+ entityHint: leads
+ source:
+ type: orm
+ acl_resource: orocrm_sales_lead_view
+ query:
+ select:
+ - lead.id
+ - lead.name
+ - lead.firstName
+ - lead.lastName
+ - lead.email
+ - lead.phoneNumber
+ - country.name as countryName
+ - address.postalCode as addressPostalCode
+ - >
+ CONCAT(
+ CASE WHEN address.regionText IS NOT NULL
+ THEN address.regionText
+ ELSE region.name
+ END, ''
+ ) as regionLabel
+ - CONCAT(lead.name, CONCAT(lead.firstName, lead.lastName)) as searchIndex
+ from:
+ - { table: %orocrm_sales.lead.entity.class%, alias: lead }
+ join:
+ left:
+ - { join: lead.address, alias: address }
+ - { join: address.country, alias: country }
+ - { join: address.region, alias: region }
+ where:
+ and:
+ - lead.status = 'new'
+ columns:
+ name:
+ label: orocrm.sales.lead.name.label
+ firstName:
+ label: orocrm.sales.lead.first_name.label
+ lastName:
+ label: orocrm.sales.lead.last_name.label
+ email:
+ label: orocrm.sales.lead.email.label
+ phoneNumber:
+ label: orocrm.sales.lead.phone_number.label
+ countryName:
+ label: orocrm.sales.lead.datagrid.country
+ regionLabel:
+ label: orocrm.sales.lead.datagrid.region
+ addressPostalCode:
+ label: orocrm.sales.lead.datagrid.postal_code
+ searchIndex: # TODO: remove this field after complex form type implementation https://magecore.atlassian.net/browse/BAP-3146
+ label: 'Search Index'
+ properties:
+ id: ~
+ sorters:
+ columns:
+ name:
+ data_name: lead.name
+ firstName:
+ data_name: lead.firstName
+ lastName:
+ data_name: lead.lastName
+ email:
+ data_name: lead.email
+ phoneNumber:
+ data_name: lead.phoneNumber
+ countryName:
+ data_name: address.country
+ regionLabel:
+ data_name: regionLabel
+ addressPostalCode:
+ data_name: addressPostalCode
+ default:
+ firstName: %oro_datagrid.extension.orm_sorter.class%::DIRECTION_ASC
+ lastName: %oro_datagrid.extension.orm_sorter.class%::DIRECTION_ASC
+ filters:
+ columns:
+ name:
+ type: string
+ data_name: lead.name
+ firstName:
+ type: string
+ data_name: lead.firstName
+ lastName:
+ type: string
+ data_name: lead.lastName
+ email:
+ type: string
+ data_name: lead.email
+ phoneNumber:
+ type: string
+ data_name: lead.phoneNumber
+ countryName:
+ type: entity
+ data_name: address.country
+ enabled: false
+ options:
+ field_options:
+ class: OroAddressBundle:Country
+ property: name
+ query_builder: @orocrm_sales.lead.datagrid_helper->getCountryFilterQueryBuilder
+ regionLabel:
+ type: string
+ data_name: regionLabel
+ enabled: false
+ addressPostalCode:
+ type: string
+ data_name: addressPostalCode
+ enabled: false
+ searchIndex:
+ type: string
+ data_name: searchIndex
+ enabled: true
+
+ # opportunities with "In progress" status for Sales Funnel flow
+ sales-funnel-opportunity-grid:
+ extended_entity_name: %orocrm_sales.opportunity.class%
+ options:
+ entityHint: opportunities
+ source:
+ type: orm
+ acl_resource: orocrm_sales_opportunity_view
+ query:
+ select:
+ - opportunity.id
+ - opportunity.name
+ - opportunity.probability
+ - CONCAT(contact.firstName, CONCAT(' ', contact.lastName)) as contactName
+ - email.email as primaryEmail
+ - >
+ CONCAT(
+ opportunity.name,
+ CASE WHEN contact IS NOT NULL
+ THEN CONCAT(contact.firstName, contact.lastName)
+ ELSE ''
+ END
+ ) as searchIndex
+ from:
+ - { table: %orocrm_sales.opportunity.class%, alias: opportunity }
+ join:
+ left:
+ - { join: opportunity.contact , alias: contact }
+ - { join: contact.emails, alias: email, conditionType: WITH, condition: 'email.primary = true' }
+ where:
+ and:
+ - opportunity.status = 'in_progress'
+ columns:
+ name:
+ label: orocrm.sales.opportunity.name.label
+ contactName:
+ label: orocrm.sales.opportunity.contact.label
+ probability:
+ label: orocrm.sales.opportunity.probability.label
+ frontend_type: percent
+ primaryEmail:
+ label: orocrm.contact.email.label
+ searchIndex: # TODO: remove this field after complex form type implementation https://magecore.atlassian.net/browse/BAP-3146
+ label: 'Search Index'
+ properties:
+ id: ~
+ sorters:
+ columns:
+ name:
+ data_name: opportunity.name
+ contactName:
+ data_name: contactName
+ probability:
+ data_name: opportunity.probability
+ primaryEmail:
+ data_name: email.email
+ filters:
+ columns:
+ name:
+ type: string
+ data_name: opportunity.name
+ contactName:
+ type: string
+ data_name: contactName
+ filter_by_having: true
+ probability:
+ type: percent
+ data_name: opportunity.probability
+ primaryEmail:
+ type: string
+ data_name: email.email
+ filter_by_having: true
+ searchIndex:
+ type: string
+ data_name: searchIndex
diff --git a/src/OroCRM/Bundle/SalesBundle/Resources/config/entity_output.yml b/src/OroCRM/Bundle/SalesBundle/Resources/config/entity_output.yml
index 48ca528c1e6..069287c9e49 100644
--- a/src/OroCRM/Bundle/SalesBundle/Resources/config/entity_output.yml
+++ b/src/OroCRM/Bundle/SalesBundle/Resources/config/entity_output.yml
@@ -7,3 +7,8 @@ OroCRM\Bundle\SalesBundle\Entity\Opportunity:
icon_class: icon-user
name: orocrm.sales.opportunity.entity_label
description: orocrm.sales.opportunity.entity_description
+
+OroCRM\Bundle\SalesBundle\Entity\SalesFunnel:
+ icon_class: icon-user
+ name: orocrm.sales.salesfunnel.entity_label
+ description: orocrm.sales.salesfunnel.entity_description
diff --git a/src/OroCRM/Bundle/SalesBundle/Resources/config/form.yml b/src/OroCRM/Bundle/SalesBundle/Resources/config/form.yml
index aa85f90f10d..b9d4f45a62a 100644
--- a/src/OroCRM/Bundle/SalesBundle/Resources/config/form.yml
+++ b/src/OroCRM/Bundle/SalesBundle/Resources/config/form.yml
@@ -8,6 +8,11 @@ parameters:
orocrm_sales.lead.form.handler.class: OroCRM\Bundle\SalesBundle\Form\Handler\LeadHandler
orocrm_sales.form.type.opportunity_select.class: OroCRM\Bundle\SalesBundle\Form\Type\OpportunitySelectType
+ orocrm_sales.form.type.lead_select.class: OroCRM\Bundle\SalesBundle\Form\Type\LeadSelectType
+
+ orocrm_sales.salesfunnel.form.type.class: OroCRM\Bundle\SalesBundle\Form\Type\SalesFunnelType
+ orocrm_sales.salesfunnel.form.type.api.class: OroCRM\Bundle\SalesBundle\Form\Type\SalesFunnelApiType
+ orocrm_sales.salesfunnel.form.handler.class: OroCRM\Bundle\SalesBundle\Form\Handler\SalesFunnelHandler
services:
orocrm_sales.opportunity.form.type:
@@ -98,3 +103,50 @@ services:
class: %orocrm_sales.form.type.opportunity_select.class%
tags:
- { name: form.type, alias: orocrm_sales_opportunity_select }
+
+ orocrm_sales.form.type.lead_select:
+ class: %orocrm_sales.form.type.lead_select.class%
+ tags:
+ - { name: form.type, alias: "orocrm_sales_lead_select" }
+
+ orocrm_sales.salesfunnel.form.type:
+ class: %orocrm_sales.salesfunnel.form.type.class%
+ tags:
+ - { name: form.type, alias: "orocrm_sales_funnel" }
+
+ orocrm_sales.salesfunnel.form.type.api:
+ class: %orocrm_sales.salesfunnel.form.type.api.class%
+ tags:
+ - { name: form.type, alias: "orocrm_sales_salesfunnel_api" }
+
+ orocrm_sales.salesfunnel.form:
+ class: Symfony\Component\Form\Form
+ factory_method: createNamed
+ factory_service: form.factory
+ arguments:
+ - "orocrm_sales_salesfunnel_form"
+ - "orocrm_sales_funnel"
+
+ orocrm_sales.salesfunnel.form.api:
+ class: Symfony\Component\Form\Form
+ factory_method: createNamed
+ factory_service: form.factory
+ arguments:
+ - "salesfunnel"
+ - "orocrm_sales_salesfunnel_api"
+
+ orocrm_sales.salesfunnel.form.handler:
+ class: %orocrm_sales.salesfunnel.form.handler.class%
+ scope: request
+ arguments:
+ - @orocrm_sales.salesfunnel.form
+ - @request
+ - @doctrine.orm.entity_manager
+
+ orocrm_sales.salesfunnel.form.handler.api:
+ class: %orocrm_sales.salesfunnel.form.handler.class%
+ scope: request
+ arguments:
+ - @orocrm_sales.salesfunnel.form.api
+ - @request
+ - @doctrine.orm.entity_manager
diff --git a/src/OroCRM/Bundle/SalesBundle/Resources/config/navigation.yml b/src/OroCRM/Bundle/SalesBundle/Resources/config/navigation.yml
index 9b173a9f799..0e164ed65f9 100644
--- a/src/OroCRM/Bundle/SalesBundle/Resources/config/navigation.yml
+++ b/src/OroCRM/Bundle/SalesBundle/Resources/config/navigation.yml
@@ -18,6 +18,12 @@ oro_menu_config:
extras:
routes: ['/^orocrm_sales_opportunity/']
description: List of opportunities
+ sales_salesfunnel_list:
+ label: orocrm.sales.salesfunnel.entity_plural_label
+ route: orocrm_sales_salesfunnel_index
+ extras:
+ routes: ['/^orocrm_sales_salesfunnel/']
+ description: List of sales funnels
shortcut_list_leads:
label: Show leads list
@@ -46,6 +52,7 @@ oro_menu_config:
children:
sales_tab:
children:
+ sales_salesfunnel_list: ~
lead_list: ~
opportunity_list: ~
shortcuts:
@@ -65,3 +72,8 @@ oro_titles:
orocrm_sales_lead_view: %%lead.name%%
orocrm_sales_lead_create: Create Lead
orocrm_sales_lead_update: %%lead.name%% - Edit
+
+ orocrm_sales_salesfunnel_index: ~
+ orocrm_sales_salesfunnel_view: %%sales_funnel.name%%
+ orocrm_sales_salesfunnel_create: Create Sales Activity
+ orocrm_sales_salesfunnel_update: %%sales_funnel.name%% - Edit
diff --git a/src/OroCRM/Bundle/SalesBundle/Resources/config/oro/routing_api.yml b/src/OroCRM/Bundle/SalesBundle/Resources/config/oro/routing_api.yml
index b4205df94cb..f97b40daf25 100644
--- a/src/OroCRM/Bundle/SalesBundle/Resources/config/oro/routing_api.yml
+++ b/src/OroCRM/Bundle/SalesBundle/Resources/config/oro/routing_api.yml
@@ -5,3 +5,7 @@ orocrm_sales_opportunity_api:
orocrm_sales_lead_api:
resource: "@OroCRMSalesBundle/Controller/Api/Rest/LeadController.php"
type: rest
+
+orocrm_sales_salesfunnel_api:
+ resource: "@OroCRMSalesBundle/Controller/Api/Rest/SalesFunnelController.php"
+ type: rest
diff --git a/src/OroCRM/Bundle/SalesBundle/Resources/config/search.yml b/src/OroCRM/Bundle/SalesBundle/Resources/config/search.yml
index b8cd9068b4c..47a8e50a5bb 100644
--- a/src/OroCRM/Bundle/SalesBundle/Resources/config/search.yml
+++ b/src/OroCRM/Bundle/SalesBundle/Resources/config/search.yml
@@ -81,3 +81,49 @@ OroCRM\Bundle\SalesBundle\Entity\Opportunity:
name: nameSuffix
target_type: text
target_fields: [nameSuffix]
+
+OroCRM\Bundle\SalesBundle\Entity\SalesFunnel:
+ alias: oro_crm_sales_funnel
+ title_fields: [name]
+ route:
+ name: orocrm_sales_salesfunnel_view
+ parameters:
+ id: id
+ search_template: OroCRMSalesBundle:SalesFunnel:searchResult.html.twig
+ fields:
+ -
+ name: name
+ target_type: text
+ target_fields: [name]
+ -
+ name: lead
+ relation_type: many-to-one
+ relation_fields:
+ -
+ name: namePrefix
+ target_type: text
+ target_fields: [namePrefix]
+ -
+ name: firstName
+ target_type: text
+ target_fields: [firstName]
+ -
+ name: middleName
+ target_type: text
+ target_fields: [middleName]
+ -
+ name: lastName
+ target_type: text
+ target_fields: [lastName]
+ -
+ name: nameSuffix
+ target_type: text
+ target_fields: [nameSuffix]
+ -
+ name: opportunity
+ relation_type: many-to-one
+ relation_fields:
+ -
+ name: name
+ target_type: text
+ target_fields: [name]
diff --git a/src/OroCRM/Bundle/SalesBundle/Resources/config/services.yml b/src/OroCRM/Bundle/SalesBundle/Resources/config/services.yml
index d16778d421d..f57fe13ed6f 100644
--- a/src/OroCRM/Bundle/SalesBundle/Resources/config/services.yml
+++ b/src/OroCRM/Bundle/SalesBundle/Resources/config/services.yml
@@ -7,6 +7,9 @@ parameters:
orocrm_sales.lead.datagrid_helper.class: Oro\Bundle\AddressBundle\Datagrid\CountryDatagridHelper
+ orocrm_sales.salesfunnel.entity.class: OroCRM\Bundle\SalesBundle\Entity\SalesFunnel
+ orocrm_sales.salesfunnel.manager.api.class: Oro\Bundle\SoapBundle\Entity\Manager\ApiEntityManager
+
services:
orocrm_sales.opportunity.manager.api:
class: %orocrm_sales.opportunity.manager.api.class%
@@ -20,15 +23,29 @@ services:
- %orocrm_sales.lead.entity.class%
- @doctrine.orm.entity_manager
+ orocrm_sales.salesfunnel.manager.api:
+ class: %orocrm_sales.salesfunnel.manager.api.class%
+ arguments:
+ - %orocrm_sales.salesfunnel.entity.class%
+ - @doctrine.orm.entity_manager
+
orocrm_sales.lead.datagrid_helper:
class: %orocrm_sales.lead.datagrid_helper.class%
tags:
- { name: kernel.event_listener, event: oro_datagrid.datgrid.build.after.sales-lead-datagrid, method: onBuildAfter }
- orocrm_sales.form.autocomplete.contact.search_handler:
- parent: oro_form.autocomplete.full_name.search_handler
+ orocrm_sales.form.autocomplete.opportunity.search_handler:
+ parent: oro_form.autocomplete.search_handler
arguments:
- %orocrm_sales.opportunity.class%
- ["name"]
tags:
- { name: oro_form.autocomplete.search_handler, alias: opportunities, acl_resource: orocrm_sales_opportunity_view }
+
+ orocrm_sales.form.autocomplete.lead.search_handler:
+ parent: oro_form.autocomplete.search_handler
+ arguments:
+ - %orocrm_sales.lead.entity.class%
+ - ["name"]
+ tags:
+ - { name: oro_form.autocomplete.search_handler, alias: leads, acl_resource: orocrm_sales_lead_view }
diff --git a/src/OroCRM/Bundle/SalesBundle/Resources/config/validation.yml b/src/OroCRM/Bundle/SalesBundle/Resources/config/validation.yml
index 777b3864f26..862be749182 100644
--- a/src/OroCRM/Bundle/SalesBundle/Resources/config/validation.yml
+++ b/src/OroCRM/Bundle/SalesBundle/Resources/config/validation.yml
@@ -1,7 +1,5 @@
OroCRM\Bundle\SalesBundle\Entity\Opportunity:
properties:
- status:
- - NotBlank: ~
name:
- NotBlank: ~
- Length:
@@ -21,8 +19,6 @@ OroCRM\Bundle\SalesBundle\Entity\Opportunity:
OroCRM\Bundle\SalesBundle\Entity\Lead:
properties:
- status:
- - NotBlank: ~
name:
- NotBlank: ~
- Length:
@@ -35,7 +31,11 @@ OroCRM\Bundle\SalesBundle\Entity\Lead:
- NotBlank: ~
- Length:
max: 255
- email:
- - Email: ~
- website:
- - Url: ~
+
+OroCRM\Bundle\SalesBundle\Entity\SalesFunnel:
+ properties:
+ name:
+ - NotBlank: ~
+ startDate:
+ - NotBlank: ~
+ - Date: ~
diff --git a/src/OroCRM/Bundle/SalesBundle/Resources/config/workflow.yml b/src/OroCRM/Bundle/SalesBundle/Resources/config/workflow.yml
index e70872a0766..3ab77e89a8d 100644
--- a/src/OroCRM/Bundle/SalesBundle/Resources/config/workflow.yml
+++ b/src/OroCRM/Bundle/SalesBundle/Resources/config/workflow.yml
@@ -2,7 +2,7 @@ workflows:
# Unqualified Sales Lead Workflow
b2b_flow_lead:
label: 'Unqualified Sales Lead'
- enabled: true
+ enabled: false
entity: OroCRM\Bundle\SalesBundle\Entity\Lead
entity_attribute: lead
steps:
@@ -254,7 +254,7 @@ workflows:
# B2B Sales Workflow
b2b_flow_sales:
label: 'B2B Sales Flow'
- enabled: true
+ enabled: false
entity: OroCRM\Bundle\SalesBundle\Entity\Opportunity
entity_attribute: opportunity
start_step: qualify
@@ -410,11 +410,10 @@ workflows:
constraints:
- NotBlank: ~
init_actions:
- - @create_object:
+ - @create_datetime:
conditions:
@empty: $close_date
parameters:
- class: '\DateTime'
attribute: $close_date
close_as_lost:
label: 'Close as Lost'
@@ -448,11 +447,10 @@ workflows:
conditions:
@not_empty: $close_reason
parameters: [$close_reason_name, $close_reason.name]
- - @create_object:
+ - @create_datetime:
conditions:
@empty: $close_date
parameters:
- class: '\DateTime'
attribute: $close_date
requalify_lost:
label: 'Requalify'
@@ -568,3 +566,720 @@ workflows:
class: OroCRM\Bundle\SalesBundle\Entity\OpportunityStatus
identifier: 'in_progress'
attribute: $opportunity.status
+
+ # B2B Sales Activity flow
+ b2b_flow_sales_funnel:
+ label: 'B2B Sales Activity Flow'
+ enabled: true
+ entity: OroCRM\Bundle\SalesBundle\Entity\SalesFunnel
+ entity_attribute: sales_funnel
+ steps:
+ new_lead:
+ label: 'New Lead'
+ order: 10
+ entity_acl:
+ lead:
+ delete: false
+ allowed_transitions:
+ - qualify
+ - disqualify
+ disqualified_lead:
+ label: 'Disqualified Lead'
+ order: 20
+ entity_acl:
+ lead:
+ update: false
+ delete: false
+ allowed_transitions:
+ - follow_up
+ - reactivate
+ new_opportunity:
+ label: 'New Opportunity'
+ order: 20
+ entity_acl:
+ opportunity:
+ delete: false
+ allowed_transitions:
+ - develop
+ - close_as_won
+ - close_as_lost
+ developed_opportunity:
+ label: 'Developed Opportunity'
+ order: 30
+ entity_acl:
+ opportunity:
+ delete: false
+ allowed_transitions:
+ - close_as_won
+ - close_as_lost
+ won_opportunity:
+ label: 'Won Opportunity'
+ order: 40
+ entity_acl:
+ opportunity:
+ update: false
+ delete: false
+ allowed_transitions:
+ - reopen
+ lost_opportunity:
+ label: 'Lost Opportunity'
+ order: 40
+ entity_acl:
+ opportunity:
+ update: false
+ delete: false
+ allowed_transitions:
+ - reopen
+
+ attributes:
+ sales_funnel_name:
+ label: "Sales Activity name"
+ type: string
+ property_path: sales_funnel.name
+ sales_funnel_start_date:
+ label: orocrm.sales.salesfunnel.start_date.label
+ type: object
+ property_path: sales_funnel.startDate
+ options:
+ class: DateTime
+ sales_funnel_owner:
+ label: orocrm.sales.salesfunnel.owner.label
+ type: entity
+ property_path: sales_funnel.owner
+ options:
+ class: Oro\Bundle\UserBundle\Entity\User
+ lead:
+ label: orocrm.sales.salesfunnel.lead.label
+ type: entity
+ property_path: sales_funnel.lead
+ options:
+ class: OroCRM\Bundle\SalesBundle\Entity\Lead
+ lead_notes:
+ label: orocrm.sales.lead.notes.label
+ type: string
+ property_path: sales_funnel.lead.notes
+ new_notes:
+ label: orocrm.sales.lead.notes.label
+ type: string
+ new_opportunity_name:
+ label: orocrm.sales.opportunity.name.label
+ type: string
+ new_account:
+ label: orocrm.account.entity_label
+ type: entity
+ options:
+ class: OroCRM\Bundle\AccountBundle\Entity\Account
+ new_company_name:
+ label: orocrm.sales.lead.company_name.label
+ type: string
+ opportunity:
+ label: orocrm.sales.salesfunnel.opportunity.label
+ type: entity
+ property_path: sales_funnel.opportunity
+ options:
+ class: OroCRM\Bundle\SalesBundle\Entity\Opportunity
+ opportunity_name:
+ label: orocrm.sales.opportunity.name.label
+ type: string
+ property_path: sales_funnel.opportunity.name
+ opportunity_notes:
+ label: orocrm.sales.lead.notes.label
+ type: string
+ property_path: sales_funnel.opportunity.notes
+ contact:
+ label: orocrm.sales.opportunity.contact.label
+ type: entity
+ property_path: sales_funnel.opportunity.contact
+ options:
+ class: OroCRM\Bundle\ContactBundle\Entity\Contact
+ account:
+ label: orocrm.sales.opportunity.account.label
+ type: entity
+ property_path: sales_funnel.opportunity.account
+ options:
+ class: OroCRM\Bundle\AccountBundle\Entity\Account
+ probability:
+ label: orocrm.sales.opportunity.probability.label
+ type: float
+ property_path: sales_funnel.opportunity.probability
+ budget_amount:
+ label: orocrm.sales.opportunity.budget_amount.label
+ type: float
+ property_path: sales_funnel.opportunity.budgetAmount
+ customer_need:
+ label: orocrm.sales.opportunity.customer_need.label
+ type: string
+ property_path: sales_funnel.opportunity.customerNeed
+ proposed_solution:
+ label: orocrm.sales.opportunity.proposed_solution.label
+ type: string
+ property_path: sales_funnel.opportunity.proposedSolution
+ close_reason_name: # temporary attribute to find close reason by its name
+ label: orocrm.sales.opportunity.close_reason.label
+ type: string
+ close_reason:
+ label: orocrm.sales.opportunity.close_reason.label
+ type: entity
+ property_path: sales_funnel.opportunity.closeReason
+ options:
+ class: OroCRM\Bundle\SalesBundle\Entity\OpportunityCloseReason
+ close_revenue:
+ label: orocrm.sales.opportunity.close_revenue.label
+ type: float
+ property_path: sales_funnel.opportunity.closeRevenue
+ close_date:
+ label: orocrm.sales.opportunity.close_date.label
+ type: object
+ property_path: sales_funnel.opportunity.closeDate
+ options:
+ class: DateTime
+
+ transitions:
+ start_from_lead:
+ label: 'Start from Lead'
+ step_to: new_lead
+ is_start: true
+ is_unavailable_hidden: true
+ display_type: page
+ frontend_options:
+ icon: 'icon-phone'
+ class: 'btn-success'
+ page:
+ parent_route: 'orocrm_sales_salesfunnel_index'
+ parent_label: orocrm.sales.salesfunnel.entity_plural_label
+ title: orocrm.sales.salesfunnel.new_entity_label
+ form_options:
+ attribute_fields:
+ sales_funnel_name:
+ form_type: text
+ options:
+ required: true
+ constraints:
+ - NotBlank: ~
+ sales_funnel_start_date:
+ form_type: oro_date
+ options:
+ required: true
+ constraints:
+ - NotBlank: ~
+ sales_funnel_owner:
+ form_type: oro_user_select
+ options:
+ required: true
+ constraints:
+ - NotBlank: ~
+ lead:
+ form_type: orocrm_sales_lead_select
+ options:
+ required: true
+ configs:
+ placeholder: orocrm.sales.form.choose_lead
+ extra_config: grid
+ grid:
+ name: sales-funnel-lead-grid
+ minimumInputLength: 0
+ properties:
+ - searchIndex
+ result_template_twig: OroCRMSalesBundle:Lead:Autocomplete/result.html.twig
+ selection_template_twig: OroCRMSalesBundle:Lead:Autocomplete/selection.html.twig
+ constraints:
+ - NotBlank: ~
+ init_actions:
+ - @create_datetime:
+ attribute: $sales_funnel_start_date
+ - @assign_active_user:
+ attribute: $sales_funnel_owner
+ transition_definition: start_definition
+ start_from_opportunity:
+ label: 'Start from Opportunity'
+ step_to: new_opportunity
+ is_start: true
+ is_unavailable_hidden: true
+ display_type: page
+ frontend_options:
+ icon: 'icon-dollar'
+ class: 'btn-success'
+ page:
+ parent_route: 'orocrm_sales_salesfunnel_index'
+ parent_label: orocrm.sales.salesfunnel.entity_plural_label
+ title: orocrm.sales.salesfunnel.new_entity_label
+ form_options:
+ attribute_fields:
+ sales_funnel_name:
+ form_type: text
+ options:
+ required: true
+ constraints:
+ - NotBlank: ~
+ sales_funnel_start_date:
+ form_type: oro_date
+ options:
+ required: true
+ constraints:
+ - NotBlank: ~
+ sales_funnel_owner:
+ form_type: oro_user_select
+ options:
+ required: true
+ constraints:
+ - NotBlank: ~
+ opportunity:
+ form_type: orocrm_sales_opportunity_select
+ options:
+ required: true
+ configs:
+ placeholder: orocrm.sales.form.choose_opportunity
+ extra_config: grid
+ grid:
+ name: sales-funnel-opportunity-grid
+ minimumInputLength: 0
+ properties:
+ - searchIndex
+ result_template_twig: OroCRMSalesBundle:Opportunity:Autocomplete/result.html.twig
+ selection_template_twig: OroCRMSalesBundle:Opportunity:Autocomplete/selection.html.twig
+ constraints:
+ - NotBlank: ~
+ init_actions:
+ - @create_datetime:
+ attribute: $sales_funnel_start_date
+ - @assign_active_user:
+ attribute: $sales_funnel_owner
+ transition_definition: start_definition
+ disqualify:
+ label: 'Disqualify'
+ step_to: disqualified_lead
+ is_unavailable_hidden: true
+ frontend_options:
+ icon: 'icon-remove'
+ transition_definition: disqualify_definition
+ follow_up:
+ label: 'Follow up'
+ step_to: disqualified_lead
+ is_unavailable_hidden: true
+ frontend_options:
+ icon: 'icon-comment'
+ form_options:
+ attribute_fields:
+ lead_notes:
+ form_type: textarea
+ options:
+ transition_definition: follow_up_definition
+ reactivate:
+ label: 'Reactivate'
+ step_to: new_lead
+ is_unavailable_hidden: true
+ frontend_options:
+ icon: 'icon-repeat'
+ transition_definition: reactivate_definition
+ qualify:
+ label: 'Qualify'
+ step_to: new_opportunity
+ is_unavailable_hidden: true
+ frontend_options:
+ icon: 'icon-ok'
+ class: 'btn-primary'
+ form_options:
+ attribute_fields:
+ new_opportunity_name:
+ form_type: text
+ options:
+ required: true
+ constraints:
+ - NotBlank: ~
+ new_account:
+ form_type: orocrm_account_select
+ options:
+ required: false
+ new_company_name:
+ form_type: text
+ options:
+ required: false
+ new_notes:
+ form_type: textarea
+ options:
+ required: false
+ attribute_default_values:
+ new_opportunity_name: $lead.name
+ new_account: $lead.account
+ new_company_name: $lead.companyName
+ new_notes: $lead.notes
+ init_actions:
+ - @find_entity: # try to find account by company name
+ conditions:
+ @and: # if account is empty and company name is specified
+ - @empty: $new_account
+ - @not_empty: $new_company_name
+ parameters:
+ class: OroCRM\Bundle\AccountBundle\Entity\Account
+ attribute: $new_account
+ where:
+ name: $new_company_name
+ case_insensitive: true
+ transition_definition: qualify_definition
+ develop:
+ label: 'Develop'
+ step_to: developed_opportunity
+ is_unavailable_hidden: true
+ frontend_options:
+ icon: 'icon-play'
+ class: 'btn-primary'
+ transition_definition: develop_definition
+ form_options:
+ attribute_fields:
+ contact:
+ form_type: orocrm_contact_select
+ options:
+ required: false
+ account:
+ form_type: orocrm_account_select
+ options:
+ required: true
+ constraints:
+ - NotBlank: ~
+ budget_amount:
+ form_type: oro_money
+ options:
+ required: false
+ constraints:
+ - Range:
+ min: 0
+ probability:
+ form_type: percent
+ options:
+ required: false
+ constraints:
+ - Range:
+ min: 0
+ max: 100
+ customer_need:
+ form_type: text
+ options:
+ required: false
+ proposed_solution:
+ form_type: text
+ options:
+ required: false
+ close_as_won:
+ label: 'Close as Won'
+ step_to: won_opportunity
+ is_unavailable_hidden: true
+ frontend_options:
+ icon: 'icon-ok-circle'
+ class: 'btn-success'
+ transition_definition: close_as_won_definition
+ form_options:
+ attribute_fields:
+ close_revenue:
+ form_type: oro_money
+ options:
+ required: true
+ constraints:
+ - NotBlank: ~
+ - Range:
+ min: 0
+ close_date:
+ form_type: oro_date
+ options:
+ required: true
+ constraints:
+ - NotBlank: ~
+ init_actions:
+ - @create_datetime:
+ conditions:
+ @empty: $close_date
+ parameters:
+ attribute: $close_date
+ close_as_lost:
+ label: 'Close as Lost'
+ step_to: lost_opportunity
+ is_unavailable_hidden: true
+ frontend_options:
+ icon: 'icon-remove-circle'
+ class: 'btn-danger'
+ transition_definition: close_as_lost_definition
+ form_options:
+ attribute_fields:
+ close_reason_name:
+ form_type: choice
+ options:
+ required: true
+ empty_value: false
+ choices:
+ outsold: 'Outsold'
+ cancelled: 'Cancelled'
+ constraints:
+ - NotBlank: ~
+ close_date:
+ form_type: oro_date
+ options:
+ required: true
+ constraints:
+ - NotBlank: ~
+ init_actions:
+ - @assign_value:
+ conditions:
+ @not_empty: $close_reason
+ parameters: [$close_reason_name, $close_reason.name]
+ - @create_datetime:
+ conditions:
+ @empty: $close_date
+ parameters:
+ attribute: $close_date
+ reopen:
+ label: 'Reopen'
+ message: |+
+ This action will reset the opportunity data and will bring the Sales Activity workflow back to the New Opportunity step.
+
+ Do you want to proceed?
+ step_to: new_opportunity
+ is_unavailable_hidden: true
+ frontend_options:
+ icon: 'icon-backward'
+ class: 'btn-primary'
+ transition_definition: reopen_definition
+
+ transition_definitions:
+ start_definition:
+ post_actions:
+ - @create_related_entity: # create Sales Funnel if it not exist yet
+ conditions:
+ @empty: [$sales_funnel.id]
+ parameters: ~
+ - @redirect: # redirect to Sales funnel view page
+ route: 'orocrm_sales_salesfunnel_view'
+ route_parameters:
+ id: $sales_funnel.id
+ disqualify_definition:
+ conditions: # if lead.status = "new"
+ @equal: [$lead.status.name, 'new']
+ post_actions: # set lead.status = "canceled"
+ - @find_entity:
+ class: OroCRM\Bundle\SalesBundle\Entity\LeadStatus
+ identifier: 'canceled'
+ attribute: $lead.status
+ follow_up_definition:
+ conditions: # if lead.status = "canceled"
+ @equal: [$lead.status.name, 'canceled']
+ reactivate_definition:
+ conditions: # if lead.status = "canceled"
+ @equal: [$lead.status.name, 'canceled']
+ post_actions: # set lead.status = "new"
+ - @find_entity:
+ class: OroCRM\Bundle\SalesBundle\Entity\LeadStatus
+ identifier: 'new'
+ attribute: $lead.status
+ qualify_definition:
+ pre_conditions: # if lead.status = "new"
+ @equal: [$lead.status.name, 'new']
+ conditions:
+ @or:
+ parameters:
+ - @not_empty: $new_company_name
+ - @not_empty: $new_account
+ message: "Company name or account must be selected."
+ post_actions: # set lead.status = "qualified"
+ - @find_entity:
+ class: OroCRM\Bundle\SalesBundle\Entity\LeadStatus
+ identifier: 'qualified'
+ attribute: $lead.status
+ - @tree: # create Contact entity
+ conditions: # if contact not specified
+ @empty: $lead.contact
+ actions:
+ - @create_entity: # create Contact based on Lead
+ class: OroCRM\Bundle\ContactBundle\Entity\Contact
+ attribute: $lead.contact
+ data:
+ namePrefix: $lead.namePrefix
+ firstName: $lead.firstName
+ middleName: $lead.middleName
+ lastName: $lead.lastName
+ nameSuffix: $lead.nameSuffix
+ jobTitle: $lead.jobTitle
+ description: $lead.name
+ - @tree: # set Contact Address
+ conditions: # if lead has address
+ @not_empty: $lead.address
+ actions:
+ - @create_entity: # create Contact Address based on Lead address
+ class: OroCRM\Bundle\ContactBundle\Entity\ContactAddress
+ attribute: $.result.address
+ data:
+ label: $lead.address.label
+ street: $lead.address.street
+ street2: $lead.address.street2
+ city: $lead.address.city
+ postalCode: $lead.address.postalCode
+ country: $lead.address.country
+ region: $lead.address.region
+ regionText: $lead.address.regionText
+ namePrefix: $lead.namePrefix
+ firstName: $lead.firstName
+ middleName: $lead.middleName
+ lastName: $lead.lastName
+ nameSuffix: $lead.nameSuffix
+ primary: true
+ - @call_method: # add Address to Contact
+ object: $lead.contact
+ method: addAddress
+ method_parameters: [$.result.address]
+ - @unset_value: # unset temporary property
+ [$.result.address]
+ - @tree: # set Contact Email
+ conditions: # if lead has email
+ @not_empty: $lead.email
+ actions:
+ - @create_entity: # create Contact Address based on Lead address
+ class: OroCRM\Bundle\ContactBundle\Entity\ContactEmail
+ attribute: $.result.email
+ data:
+ email: $lead.email
+ owner: $lead.contact
+ primary: true
+ - @call_method: # add Email to Contact
+ object: $lead.contact
+ method: addEmail
+ method_parameters: [$.result.email]
+ - @unset_value: # unset temporary property
+ [$.result.email]
+ - @tree: # set Contact Phone
+ conditions: # if lead has phone
+ @not_empty: $lead.phoneNumber
+ actions:
+ - @create_entity: # create Contact Address based on Lead address
+ class: OroCRM\Bundle\ContactBundle\Entity\ContactPhone
+ attribute: $.result.phone
+ data:
+ phone: $lead.phoneNumber
+ primary: true
+ - @call_method: # add Phone to Contact
+ object: $lead.contact
+ method: addPhone
+ method_parameters: [$.result.phone]
+ - @unset_value: # unset temporary property
+ [$.result.phone]
+ - @tree: # create and set Account
+ conditions:
+ @and: # if account not selected and company name is selected
+ - @empty: $new_account
+ - @not_empty: $new_company_name
+ actions:
+ - @find_entity: # try to find account by company name
+ class: OroCRM\Bundle\AccountBundle\Entity\Account
+ attribute: $new_account
+ where:
+ name: $new_company_name
+ case_insensitive: true
+ - @create_entity: # if account not found - create new one
+ conditions:
+ @empty: $new_account
+ parameters:
+ class: OroCRM\Bundle\AccountBundle\Entity\Account
+ attribute: $new_account
+ data:
+ name: $new_company_name
+ extendPhone: $lead.phoneNumber
+ extendEmail: $lead.email
+ extendWebsite: $lead.website
+ extendEmployees: $lead.numberOfEmployees
+ - @create_entity: # create an opportunity
+ class: OroCRM\Bundle\SalesBundle\Entity\Opportunity
+ attribute: $opportunity
+ data:
+ name: $new_opportunity_name
+ contact: $lead.contact
+ account: $new_account
+ lead: $lead
+ notes: $new_notes
+ - @find_entity: # set status "In progress" to opportunity
+ class: OroCRM\Bundle\SalesBundle\Entity\OpportunityStatus
+ identifier: 'in_progress'
+ attribute: $opportunity.status
+ develop_definition:
+ pre_conditions: # if opportunity.status = "in_progress"
+ @equal:
+ message: 'Opportunity must be in status "In progress"'
+ parameters: [$opportunity.status.name, 'in_progress']
+ conditions: # if opportunity.status = "in_progress"
+ @and:
+ - @greater_or_equal:
+ message: 'Budget amout must be greater or equal to 0'
+ parameters: [$budget_amount, 0]
+ - @and:
+ message: 'Probality must be between 0 and 100 percents'
+ parameters:
+ - @greater_or_equal: [$probability, 0]
+ - @less_or_equal: [$probability, 1]
+ close_as_won_definition:
+ pre_conditions:
+ @equal:
+ message: 'Opportunity must be in status "In progress"'
+ parameters: [$opportunity.status.name, 'in_progress']
+ conditions: # if opportunity.status = "in_progress" and required data is entered
+ @and:
+ - @not_empty:
+ message: 'Close date must be set'
+ parameters: $close_date
+ - @not_empty:
+ message: 'Close revenue must be set'
+ parameters: $close_revenue
+ - @greater_or_equal:
+ message: 'Close revenue must be greater or equal to 0'
+ parameters: [$close_revenue, 0]
+ post_actions: # update opportunity properties, set opportunity.status = "won"
+ - @find_entity:
+ class: OroCRM\Bundle\SalesBundle\Entity\OpportunityStatus
+ identifier: 'won'
+ attribute: $opportunity.status
+ - @find_entity:
+ class: OroCRM\Bundle\SalesBundle\Entity\OpportunityCloseReason
+ identifier: 'won'
+ attribute: $close_reason
+ - @assign_value:
+ - [$probability, 1]
+ - [$close_reason_name, 'won']
+ close_as_lost_definition:
+ pre_conditions: # opportunity.status = "in_progress" and required data is entered
+ @equal:
+ message: 'Opportunity must be in status "In progress"'
+ parameters: [$opportunity.status.name, 'in_progress']
+ conditions:
+ @and:
+ - @not_empty:
+ message: 'Close date must be set'
+ parameters: $close_date
+ - @not_empty:
+ message: 'Close reason must be set'
+ parameters: $close_reason_name
+ post_actions: # update opportunity properties, set opportunity.status = "lost"
+ - @find_entity:
+ class: OroCRM\Bundle\SalesBundle\Entity\OpportunityStatus
+ identifier: 'lost'
+ attribute: $opportunity.status
+ - @find_entity:
+ class: OroCRM\Bundle\SalesBundle\Entity\OpportunityCloseReason
+ identifier: $close_reason_name
+ attribute: $close_reason
+ - @assign_value:
+ - [$probability, 0]
+ - [$close_revenue, 0]
+ reopen_definition:
+ conditions:
+ @or:
+ message: 'Opportunity must be in status "Won" or "Lost"'
+ parameters:
+ - @equal: [$opportunity.status.name, 'won']
+ - @equal: [$opportunity.status.name, 'lost']
+ post_actions:
+ - @find_entity:
+ class: OroCRM\Bundle\SalesBundle\Entity\OpportunityStatus
+ identifier: 'in_progress'
+ attribute: $opportunity.status
+ - @assign_value:
+ - [$budget_amount, ~]
+ - [$customer_need, ~]
+ - [$proposed_solution, ~]
+ - [$probability, ~]
+ - [$close_revenue, ~]
+ - [$close_reason, ~]
+ - [$close_date, ~]
diff --git a/src/OroCRM/Bundle/SalesBundle/Resources/translations/messages.en.yml b/src/OroCRM/Bundle/SalesBundle/Resources/translations/messages.en.yml
index 8c938ea539d..9694bea5825 100644
--- a/src/OroCRM/Bundle/SalesBundle/Resources/translations/messages.en.yml
+++ b/src/OroCRM/Bundle/SalesBundle/Resources/translations/messages.en.yml
@@ -21,9 +21,11 @@ orocrm:
controller:
lead.saved.message: "Lead saved"
opportunity.saved.message: "Opportunity saved"
+ sales_funnel.saved.message: "Sales activity saved"
form:
choose_opportunity: 'Choose an opportunity....'
+ choose_lead: 'Choose a lead....'
#
# OroCRM/Bundle/SalesBundle/Entity/LeadStatus.php
@@ -67,7 +69,8 @@ orocrm:
owner.label: Owner
notes.label: Notes
lead.label: Lead
- b2b_flow_sales.step.label: Step
+ workflow_item.label: Workflow Item
+ workflow_step.label: Step
datagrid:
view: View
@@ -115,7 +118,7 @@ orocrm:
notes.label: Notes
opportunities.label: Opportunities
workflow_item.label: Workflow Item
- workflow_step.label: Workflow Step
+ workflow_step.label: Step
datagrid:
country: Country
@@ -124,3 +127,23 @@ orocrm:
view: View
update: Update
delete: Delete
+
+ salesfunnel:
+ entity_label: Sales Activity
+ entity_plural_label: Sales Activity
+ new_entity_label: New Sales Activity
+ id.label: Id
+ created_at.label: Created
+ updated_at.label: Updated
+ name.label: Name
+ start_date.label: Start Date
+ lead.label: Lead
+ opportunity.label: Opportunity
+ owner.label: Owner
+ workflow_item.label: Workflow Item
+ workflow_step.label: Step
+
+ datagrid:
+ view: View
+ update: Update
+ delete: Delete
diff --git a/src/OroCRM/Bundle/SalesBundle/Resources/views/Lead/Autocomplete/result.html.twig b/src/OroCRM/Bundle/SalesBundle/Resources/views/Lead/Autocomplete/result.html.twig
new file mode 100644
index 00000000000..d22759eb2cd
--- /dev/null
+++ b/src/OroCRM/Bundle/SalesBundle/Resources/views/Lead/Autocomplete/result.html.twig
@@ -0,0 +1 @@
+<%= highlight(name) %><%if (typeof firstName != 'undefined' && typeof lastName != 'undefined') { %> - <%= highlight(firstName) %> <%= highlight(lastName) %><% } %>
diff --git a/src/OroCRM/Bundle/SalesBundle/Resources/views/Lead/Autocomplete/selection.html.twig b/src/OroCRM/Bundle/SalesBundle/Resources/views/Lead/Autocomplete/selection.html.twig
new file mode 100644
index 00000000000..680b26e55b6
--- /dev/null
+++ b/src/OroCRM/Bundle/SalesBundle/Resources/views/Lead/Autocomplete/selection.html.twig
@@ -0,0 +1 @@
+<%= name %><%if (typeof firstName != 'undefined' && typeof lastName != 'undefined') { %> - <%= firstName %> <%= lastName %><% } %>
diff --git a/src/OroCRM/Bundle/SalesBundle/Resources/views/Lead/update.html.twig b/src/OroCRM/Bundle/SalesBundle/Resources/views/Lead/update.html.twig
index c5a55a9be56..bc396010536 100644
--- a/src/OroCRM/Bundle/SalesBundle/Resources/views/Lead/update.html.twig
+++ b/src/OroCRM/Bundle/SalesBundle/Resources/views/Lead/update.html.twig
@@ -34,28 +34,6 @@
{{ UI.saveAndStayButton() }}
{% endif %}
{{ UI.saveAndCloseButton() }}
-
- {% if resource_granted('orocrm_sales_lead_create')
- and resource_granted('oro_workflow')
- and form.vars.value.id is empty
- %}
-
-
-
-
-
- {% endif %}
{% endblock %}
{% block pageHeader %}
diff --git a/src/OroCRM/Bundle/SalesBundle/Resources/views/Opportunity/Autocomplete/result.html.twig b/src/OroCRM/Bundle/SalesBundle/Resources/views/Opportunity/Autocomplete/result.html.twig
index bea621c5300..3c1612f163a 100644
--- a/src/OroCRM/Bundle/SalesBundle/Resources/views/Opportunity/Autocomplete/result.html.twig
+++ b/src/OroCRM/Bundle/SalesBundle/Resources/views/Opportunity/Autocomplete/result.html.twig
@@ -1 +1 @@
-<%= highlight(name) %>
+<%= highlight(name) %><% if (typeof contactName != 'undefined') { %> - <%= highlight(contactName) %><% } %>
diff --git a/src/OroCRM/Bundle/SalesBundle/Resources/views/Opportunity/Autocomplete/selection.html.twig b/src/OroCRM/Bundle/SalesBundle/Resources/views/Opportunity/Autocomplete/selection.html.twig
index 8229b16dd9f..0d532eaf44f 100644
--- a/src/OroCRM/Bundle/SalesBundle/Resources/views/Opportunity/Autocomplete/selection.html.twig
+++ b/src/OroCRM/Bundle/SalesBundle/Resources/views/Opportunity/Autocomplete/selection.html.twig
@@ -1 +1 @@
-<%= name %>
+<%= name %><% if (typeof contactName != 'undefined') { %> - <%= contactName %><% } %>
diff --git a/src/OroCRM/Bundle/SalesBundle/Resources/views/SalesFunnel/index.html.twig b/src/OroCRM/Bundle/SalesBundle/Resources/views/SalesFunnel/index.html.twig
new file mode 100644
index 00000000000..5b73ff1682e
--- /dev/null
+++ b/src/OroCRM/Bundle/SalesBundle/Resources/views/SalesFunnel/index.html.twig
@@ -0,0 +1,9 @@
+{% extends 'OroUIBundle:actions:index.html.twig' %}
+{% import 'OroUIBundle::macros.html.twig' as UI %}
+{% set gridName = 'sales-funnel-grid' %}
+{% set pageTitle = 'orocrm.sales.salesfunnel.entity_plural_label'|trans %}
+
+{% block content %}
+ {% set buttonsPlaceholderData = {'entity_class': entityClass} %}
+ {{ parent() }}
+{% endblock %}
diff --git a/src/OroCRM/Bundle/SalesBundle/Resources/views/SalesFunnel/searchResult.html.twig b/src/OroCRM/Bundle/SalesBundle/Resources/views/SalesFunnel/searchResult.html.twig
new file mode 100644
index 00000000000..811de66d59e
--- /dev/null
+++ b/src/OroCRM/Bundle/SalesBundle/Resources/views/SalesFunnel/searchResult.html.twig
@@ -0,0 +1,18 @@
+{#
+ Available variables:
+ * entity - user entity OroCRM\Bundle\SalesBundle\Entity\SalesFunnel or null
+ * indexer_item - indexer item Oro\Bundle\SearchBundle\Query\Result\Item
+#}
+{% extends 'OroSearchBundle:Search:searchResultItem.html.twig' %}
+
+{% set showImage = false %}
+
+{% set recordUrl = indexer_item.recordUrl %}
+{% set title = entity ? entity.name : indexer_item.recordTitle %}
+
+{% set entityType = 'orocrm.sales.salesfunnel.entity_label'|trans %}
+
+{% set entityInfo = [
+ {'title': 'orocrm.sales.salesfunnel.created_at.label'|trans, 'value': entity.createdAt ? entity.createdAt|oro_format_datetime : 'N/A'},
+ {'title': 'orocrm.sales.salesfunnel.updated_at.label'|trans, 'value': entity.updatedAt ? entity.updatedAt|oro_format_datetime : 'N/A'},
+] %}
diff --git a/src/OroCRM/Bundle/SalesBundle/Resources/views/SalesFunnel/update.html.twig b/src/OroCRM/Bundle/SalesBundle/Resources/views/SalesFunnel/update.html.twig
new file mode 100644
index 00000000000..76792efdcad
--- /dev/null
+++ b/src/OroCRM/Bundle/SalesBundle/Resources/views/SalesFunnel/update.html.twig
@@ -0,0 +1,111 @@
+{% extends 'OroUIBundle:actions:update.html.twig' %}
+{% form_theme form with ['OroAddressBundle:Include:fields.html.twig', 'OroFormBundle:Form:fields.html.twig'] %}
+
+{% oro_title_set({params : {"%sales_funnel.name%": entity.name} }) %}
+{% set audit_entity_class = 'OroCRM_Bundle_SalesBundle_Entity_SalesFunnel' %}
+{% set title = form.vars.value.id
+ ? entity.name ~ ' - ' ~ 'Update'|trans ~ ' ' ~ 'orocrm.sales.salesfunnel.entity_label'|trans
+ : 'New'|trans ~ ' ' ~ 'orocrm.sales.salesfunnel.entity_label'|trans
+%}
+{% set formAction = form.vars.value.id ? path('orocrm_sales_salesfunnel_update', { 'id': form.vars.value.id }) : path('orocrm_sales_salesfunnel_create') %}
+
+{% block head_script %}
+ {{ parent() }}
+
+ {% block stylesheets %}
+ {{ form_stylesheet(form) }}
+ {% endblock %}
+{% endblock %}
+
+{% block navButtons %}
+ {% if form.vars.value.id and resource_granted('DELETE', form.vars.value) %}
+ {{ UI.deleteButton({
+ 'dataUrl': path('oro_api_delete_salesfunnel', {'id': form.vars.value.id}),
+ 'dataRedirect': path('orocrm_sales_salesfunnel_index'),
+ 'aCss': 'no-hash remove-button',
+ 'id': 'btn-remove-sales-funnel',
+ 'dataId': form.vars.value.id,
+ 'entity_label': 'orocrm.sales.salesfunnel.entity_label'|trans
+ }) }}
+ {{ UI.buttonSeparator() }}
+ {% endif %}
+ {{ UI.cancelButton(path('orocrm_sales_salesfunnel_index')) }}
+ {% if form.vars.value.id or resource_granted('orocrm_sales_salesfunnel_update') %}
+ {{ UI.saveAndStayButton() }}
+ {% endif %}
+ {{ UI.saveAndCloseButton() }}
+
+ {% if resource_granted('orocrm_sales_salesfunnel_create')
+ and resource_granted('oro_workflow')
+ and form.vars.value.id is empty
+ %}
+ {% endif %}
+{% endblock %}
+
+{% block pageHeader %}
+ {% if form.vars.value.id %}
+ {% set breadcrumbs = {
+ 'entity': form.vars.value,
+ 'indexPath': path('orocrm_sales_salesfunnel_index'),
+ 'indexLabel': 'orocrm.sales.salesfunnel.entity_plural_label'|trans,
+ 'entityTitle': entity.name
+ } %}
+ {{ parent() }}
+ {% else %}
+ {% include 'OroUIBundle::page_title_block.html.twig' %}
+ {% endif %}
+{% endblock pageHeader %}
+
+{% block stats %}
+ {{ 'orocrm.sales.salesfunnel.created_at.label'|trans }}: {{ entity.createdAt ? entity.createdAt|oro_format_datetime : 'N/A' }}
+ {{ 'orocrm.sales.salesfunnel.updated_at.label'|trans }}: {{ entity.updatedAt ? entity.updatedAt|oro_format_datetime : 'N/A' }}
+{% endblock stats %}
+
+{% block content_data %}
+ {% set id = 'sales-funnel-management' %}
+
+ {% set formFields = [] %}
+ {% if form.owner is defined %}
+ {% set formFields = formFields|merge([form_row(form.owner)]) %}
+ {% endif %}
+ {% set formFields = formFields|merge([
+ form_row(form.name),
+ form_row(form.startDate),
+ ]) %}
+
+ {% set dataBlocks = [{
+ 'title': 'General',
+ 'class': 'active',
+ 'subblocks': [
+ {
+ 'title': 'Sales Activity Information',
+ 'data': formFields
+ }
+ ]
+ }]
+ %}
+
+ {% if form.additional is defined and form.additional.children|length > 0 %}
+ {% set additionalData = [] %}
+ {% for value in form.additional %}
+ {% set additionalData = additionalData|merge([form_row(value)]) %}
+ {% endfor %}
+
+ {% set dataBlocks = dataBlocks|merge([{
+ 'title': 'Additional',
+ 'subblocks': [{
+ 'title': '',
+ 'useSpan': false,
+ 'data' : additionalData
+ }]
+ }] ) %}
+ {% endif %}
+
+ {% set data =
+ {
+ 'formErrors': form_errors(form)? form_errors(form) : null,
+ 'dataBlocks': dataBlocks,
+ }
+ %}
+ {{ parent() }}
+{% endblock content_data %}
diff --git a/src/OroCRM/Bundle/SalesBundle/Resources/views/SalesFunnel/view.html.twig b/src/OroCRM/Bundle/SalesBundle/Resources/views/SalesFunnel/view.html.twig
new file mode 100644
index 00000000000..e0e912089ff
--- /dev/null
+++ b/src/OroCRM/Bundle/SalesBundle/Resources/views/SalesFunnel/view.html.twig
@@ -0,0 +1,73 @@
+{% extends 'OroUIBundle:actions:view.html.twig' %}
+{% import 'OroUIBundle::macros.html.twig' as macros %}
+
+{% oro_title_set({params : {"%sales_funnel.name%": entity.name} }) %}
+{% set audit_entity_class = 'OroCRM_Bundle_SalesBundle_Entity_SalesFunnel' %}
+
+{% block navButtons %}
+ {% if resource_granted('EDIT', entity) %}
+ {{ UI.editButton({
+ 'path' : path('orocrm_sales_salesfunnel_update', { 'id': entity.id }),
+ 'entity_label': 'orocrm.sales.salesfunnel.entity_label'|trans
+ }) }}
+ {% endif %}
+ {% if resource_granted('DELETE', entity) %}
+ {{ UI.deleteButton({
+ 'dataUrl': path('oro_api_delete_salesfunnel', {'id': entity.id}),
+ 'dataRedirect': path('orocrm_sales_salesfunnel_index'),
+ 'aCss': 'no-hash remove-button',
+ 'id': 'btn-remove-sales-funnel',
+ 'dataId': entity.id,
+ 'entity_label': 'orocrm.sales.salesfunnel.entity_label'|trans
+ }) }}
+ {% endif %}
+{% endblock navButtons %}
+
+{% block stats %}
+ {{ 'orocrm.sales.salesfunnel.created_at.label'|trans }}: {{ entity.createdAt ? entity.createdAt|oro_format_datetime : 'N/A' }}
+ {{ 'orocrm.sales.salesfunnel.updated_at.label'|trans }}: {{ entity.updatedAt ? entity.updatedAt|oro_format_datetime : 'N/A' }}
+{% endblock stats %}
+
+{% block pageHeader %}
+ {% set breadcrumbs = {
+ 'entity': entity,
+ 'indexPath': path('orocrm_sales_salesfunnel_index'),
+ 'indexLabel': 'orocrm.sales.salesfunnel.entity_plural_label'|trans,
+ 'entityTitle': entity.name
+ } %}
+ {{ parent() }}
+{% endblock pageHeader %}
+
+{% block content_data %}
+ {% set informationWidget %}
+ {{ oro_widget_render({
+ 'widgetType': 'block',
+ 'url': path('orocrm_sales_salesfunnel_info', {id: entity.id}),
+ }) }}
+ {% endset %}
+
+ {% set dataBlocks = [
+ {
+ 'title': 'General Information'|trans,
+ 'class': 'active',
+ 'subblocks': [{'data' : [informationWidget] }]
+ }
+ ] %}
+
+ {% if entity.opportunity %}
+ {% set opportunityInfoWidget %}
+ {{ oro_widget_render({
+ 'widgetType': 'block',
+ 'url': path('orocrm_sales_opportunity_info', {id: entity.opportunity.id})
+ }) }}
+ {% endset %}
+ {% set dataBlocks = dataBlocks|merge([{
+ 'title': 'Opportunity Information'|trans,
+ 'subblocks': [{'data' : [opportunityInfoWidget] }]
+ }]) %}
+ {% endif %}
+
+ {% set id = 'salesFunnelView' %}
+ {% set data = {'dataBlocks': dataBlocks} %}
+ {{ parent() }}
+{% endblock content_data %}
diff --git a/src/OroCRM/Bundle/SalesBundle/Resources/views/SalesFunnel/widget/info.html.twig b/src/OroCRM/Bundle/SalesBundle/Resources/views/SalesFunnel/widget/info.html.twig
new file mode 100644
index 00000000000..f2eda4d8e16
--- /dev/null
+++ b/src/OroCRM/Bundle/SalesBundle/Resources/views/SalesFunnel/widget/info.html.twig
@@ -0,0 +1,35 @@
+{% import 'OroUIBundle::macros.html.twig' as ui %}
+{% import 'OroEmailBundle::macros.html.twig' as email %}
+{#{% import 'OroEntityConfigBundle::macros.html.twig' as entityConfig %}#}
+
+
diff --git a/src/OroCRM/Bundle/SalesBundle/Tests/Functional/API/RestLeadTest.php b/src/OroCRM/Bundle/SalesBundle/Tests/Functional/API/RestLeadTest.php
new file mode 100644
index 00000000000..48ea7287802
--- /dev/null
+++ b/src/OroCRM/Bundle/SalesBundle/Tests/Functional/API/RestLeadTest.php
@@ -0,0 +1,163 @@
+client = static::createClient(
+ array(),
+ ToolsAPI::generateWsseHeader()
+ );
+ }
+
+ /**
+ * @return array
+ */
+ public function testPostLead()
+ {
+ $request = array(
+ "lead" => array(
+ 'name' => 'lead_name_' . mt_rand(1, 500),
+ 'firstName' => 'first_name_' . mt_rand(1, 500),
+ 'lastName' => 'last_name_' . mt_rand(1, 500),
+ 'owner' => '1'
+ )
+ );
+
+ $this->client->request(
+ 'POST',
+ $this->client->generate('oro_api_post_lead'),
+ $request
+ );
+ $result = $this->client->getResponse();
+ ToolsAPI::assertJsonResponse($result, 201);
+ $result = ToolsAPI::jsonToArray($result->getContent());
+
+ $request['id'] = $result['id'];
+ return $request;
+ }
+
+ /**
+ * @param $request
+ * @depends testPostLead
+ * @return mixed
+ */
+ public function testGetLead($request)
+ {
+ $this->client->request(
+ 'GET',
+ $this->client->generate('oro_api_get_lead', array('id' => $request['id']))
+ );
+
+ $result = $this->client->getResponse();
+ ToolsAPI::assertJsonResponse($result, 200);
+ $result = ToolsAPI::jsonToArray($result->getContent());
+
+ $this->assertEquals($request['id'], $result['id']);
+ $this->assertEquals($request['lead']['firstName'], $result['firstName']);
+ $this->assertEquals($request['lead']['lastName'], $result['lastName']);
+ $this->assertEquals($request['lead']['name'], $result['name']);
+ $this->assertEquals('New', $result['status']);
+ // TODO: incomplete CRM-816
+ //$this->assertEquals($request['lead']['owner'], $result['owner']['id']);
+ return $request;
+ }
+
+ /**
+ * @param $request
+ * @depends testGetLead
+ * @return mixed
+ */
+ public function testPutLead($request)
+ {
+
+ $request['lead']['firstName'] .= '_updated';
+ $request['lead']['lastName'] .= '_updated';
+ $request['lead']['name'] .= '_updated';
+
+ $this->client->request(
+ 'PUT',
+ $this->client->generate('oro_api_put_lead', array('id' => $request['id'])),
+ $request
+ );
+
+ $result = $this->client->getResponse();
+ ToolsAPI::assertJsonResponse($result, 204);
+
+ $this->client->request(
+ 'GET',
+ $this->client->generate('oro_api_get_lead', array('id' => $request['id']))
+ );
+
+ $result = $this->client->getResponse();
+ ToolsAPI::assertJsonResponse($result, 200);
+ $result = ToolsAPI::jsonToArray($result->getContent());
+
+ $this->assertEquals($request['id'], $result['id']);
+ $this->assertEquals($request['lead']['firstName'], $result['firstName']);
+ $this->assertEquals($request['lead']['lastName'], $result['lastName']);
+ $this->assertEquals($request['lead']['name'], $result['name']);
+ $this->assertEquals('New', $result['status']);
+
+ return $request;
+ }
+
+ /**
+ * @depends testPutLead
+ */
+ public function testGetLeads($request)
+ {
+ $this->client->request(
+ 'GET',
+ $this->client->generate('oro_api_get_leads')
+ );
+ $result = $this->client->getResponse();
+ ToolsAPI::assertJsonResponse($result, 200);
+ $result = ToolsApi::jsonToArray($result->getContent());
+
+ $this->assertNotEmpty($result);
+
+ $result = reset($result);
+ $this->assertEquals($request['id'], $result['id']);
+ $this->assertEquals($request['lead']['firstName'], $result['firstName']);
+ $this->assertEquals($request['lead']['lastName'], $result['lastName']);
+ $this->assertEquals($request['lead']['name'], $result['name']);
+ $this->assertEquals('New', $result['status']);
+ }
+
+ /**
+ * @depends testPutLead
+ */
+ public function testDeleteLead($request)
+ {
+ $this->client->request(
+ 'DELETE',
+ $this->client->generate('oro_api_delete_lead', array('id' => $request['id']))
+ );
+ $result = $this->client->getResponse();
+ ToolsAPI::assertJsonResponse($result, 204);
+
+ $this->client->request(
+ 'GET',
+ $this->client->generate('oro_api_get_lead', array('id' => $request['id']))
+ );
+
+ $result = $this->client->getResponse();
+ ToolsAPI::assertJsonResponse($result, 404);
+ }
+}
diff --git a/src/OroCRM/Bundle/SalesBundle/Tests/Functional/API/RestOpportunityTest.php b/src/OroCRM/Bundle/SalesBundle/Tests/Functional/API/RestOpportunityTest.php
new file mode 100644
index 00000000000..d45c76f8d09
--- /dev/null
+++ b/src/OroCRM/Bundle/SalesBundle/Tests/Functional/API/RestOpportunityTest.php
@@ -0,0 +1,173 @@
+client = static::createClient(
+ array(),
+ ToolsAPI::generateWsseHeader()
+ );
+ }
+
+ protected function preAccountData()
+ {
+ $request = array(
+ "account" => array (
+ "name" => 'Account_name_opportunity',
+ "owner" => '1',
+ )
+ );
+ $this->client->request(
+ 'POST',
+ $this->client->generate('oro_api_post_account'),
+ $request
+ );
+ $result = $this->client->getResponse();
+ ToolsAPI::assertJsonResponse($result, 201);
+ $result = ToolsAPI::jsonToArray($result->getContent());
+ return $result['id'];
+ }
+ /**
+ * @return array
+ */
+ public function testPostOpportunity()
+ {
+ $request = array(
+ "opportunity" => array(
+ 'name' => 'opportunity_name_' . mt_rand(1, 500),
+ 'owner' => '1',
+ 'account' => $this->preAccountData()
+ )
+ );
+
+ $this->client->request(
+ 'POST',
+ $this->client->generate('oro_api_post_opportunity'),
+ $request
+ );
+ $result = $this->client->getResponse();
+ ToolsAPI::assertJsonResponse($result, 201);
+ $result = ToolsAPI::jsonToArray($result->getContent());
+
+ $request['id'] = $result['id'];
+ return $request;
+ }
+
+ /**
+ * @param $request
+ * @depends testPostOpportunity
+ * @return mixed
+ */
+ public function testGetOpportunity($request)
+ {
+ $this->client->request(
+ 'GET',
+ $this->client->generate('oro_api_get_opportunity', array('id' => $request['id']))
+ );
+
+ $result = $this->client->getResponse();
+ ToolsAPI::assertJsonResponse($result, 200);
+ $result = ToolsAPI::jsonToArray($result->getContent());
+
+ $this->assertEquals($request['id'], $result['id']);
+ $this->assertEquals($request['opportunity']['name'], $result['name']);
+ $this->assertEquals('In Progress', $result['status']);
+ $this->assertEquals('Account_name_opportunity', $result['account']);
+ // TODO: incomplete CRM-816
+ //$this->assertEquals($request['opportunity']['owner'], $result['owner']['id']);
+ return $request;
+ }
+
+ /**
+ * @param $request
+ * @depends testGetOpportunity
+ * @return mixed
+ */
+ public function testPutOpportunity($request)
+ {
+
+ $request['opportunity']['name'] .= '_updated';
+
+ $this->client->request(
+ 'PUT',
+ $this->client->generate('oro_api_put_opportunity', array('id' => $request['id'])),
+ $request
+ );
+
+ $result = $this->client->getResponse();
+ ToolsAPI::assertJsonResponse($result, 204);
+
+ $this->client->request(
+ 'GET',
+ $this->client->generate('oro_api_get_opportunity', array('id' => $request['id']))
+ );
+
+ $result = $this->client->getResponse();
+ ToolsAPI::assertJsonResponse($result, 200);
+ $result = ToolsAPI::jsonToArray($result->getContent());
+
+ $this->assertEquals($request['id'], $result['id']);
+ $this->assertEquals($request['opportunity']['name'], $result['name']);
+ $this->assertEquals('In Progress', $result['status']);
+
+ return $request;
+ }
+
+ /**
+ * @depends testPutOpportunity
+ */
+ public function testGetOpportunitys($request)
+ {
+ $this->client->request(
+ 'GET',
+ $this->client->generate('oro_api_get_opportunities')
+ );
+ $result = $this->client->getResponse();
+ ToolsAPI::assertJsonResponse($result, 200);
+ $result = ToolsApi::jsonToArray($result->getContent());
+
+ $this->assertNotEmpty($result);
+
+ $result = reset($result);
+ $this->assertEquals($request['id'], $result['id']);
+ $this->assertEquals($request['opportunity']['name'], $result['name']);
+ $this->assertEquals('In Progress', $result['status']);
+ }
+
+ /**
+ * @depends testPutOpportunity
+ */
+ public function testDeleteOpportunity($request)
+ {
+ $this->client->request(
+ 'DELETE',
+ $this->client->generate('oro_api_delete_opportunity', array('id' => $request['id']))
+ );
+ $result = $this->client->getResponse();
+ ToolsAPI::assertJsonResponse($result, 204);
+
+ $this->client->request(
+ 'GET',
+ $this->client->generate('oro_api_get_opportunity', array('id' => $request['id']))
+ );
+
+ $result = $this->client->getResponse();
+ ToolsAPI::assertJsonResponse($result, 404);
+ }
+}
diff --git a/src/OroCRM/Bundle/SalesBundle/Tests/Selenium/Pages/Lead.php b/src/OroCRM/Bundle/SalesBundle/Tests/Selenium/Pages/Lead.php
index 097d6dfa2bd..fe096021239 100644
--- a/src/OroCRM/Bundle/SalesBundle/Tests/Selenium/Pages/Lead.php
+++ b/src/OroCRM/Bundle/SalesBundle/Tests/Selenium/Pages/Lead.php
@@ -338,14 +338,6 @@ public function checkStatus($status)
return $this;
}
- public function reactivate()
- {
- $this->test->byXpath("//div[@class='btn-group']/a[@id='transition-b2b_flow_lead-reactivate']")->click();
- $this->waitPageToLoad();
- $this->waitForAjax();
- return $this;
- }
-
public function edit()
{
$this->test->byXpath("//div[@class='pull-left btn-group icons-holder']/a[@title = 'Edit lead']")->click();
diff --git a/src/OroCRM/Bundle/SalesBundle/Tests/Selenium/Pages/SalesActivities.php b/src/OroCRM/Bundle/SalesBundle/Tests/Selenium/Pages/SalesActivities.php
new file mode 100644
index 00000000000..88ad3fed530
--- /dev/null
+++ b/src/OroCRM/Bundle/SalesBundle/Tests/Selenium/Pages/SalesActivities.php
@@ -0,0 +1,50 @@
+redirectUrl = self::URL;
+ parent::__construct($testCase, $redirect);
+ }
+
+ public function startFromLead()
+ {
+ $this->test->byXPath("//a[@title='Start from Lead']")->click();
+ $this->waitPageToLoad();
+ $this->waitForAjax();
+
+ return new SalesActivity($this->test);
+ }
+
+ public function startFromOpportunity()
+ {
+ $this->test->byXPath("//a[@title='Start from Opportunity']")->click();
+ $this->waitPageToLoad();
+ $this->waitForAjax();
+
+ return new SalesActivity($this->test);
+ }
+
+ public function open($entityData = array())
+ {
+ $contact = $this->getEntity($entityData);
+ $contact->click();
+ sleep(1);
+ $this->waitPageToLoad();
+ $this->waitForAjax();
+
+ return new SalesActivity($this->test);
+ }
+}
diff --git a/src/OroCRM/Bundle/SalesBundle/Tests/Selenium/Pages/SalesActivity.php b/src/OroCRM/Bundle/SalesBundle/Tests/Selenium/Pages/SalesActivity.php
new file mode 100644
index 00000000000..99af3e03d6c
--- /dev/null
+++ b/src/OroCRM/Bundle/SalesBundle/Tests/Selenium/Pages/SalesActivity.php
@@ -0,0 +1,124 @@
+activityname = $this->test->byId('oro_workflow_transition_sales_funnel_name');
+ $this->activityname->clear();
+ $this->activityname->value($name);
+ return $this;
+ }
+
+ public function setStartDate($date)
+ {
+ $this->startdate = $this->test->byId('oro_workflow_transition_sales_funnel_name');
+ $this->startdate->clear();
+ $this->startdate->value($date);
+ return $this;
+ }
+
+ public function setOwner($owner)
+ {
+ $this->owner = $this->test->byXpath("//div[@id='s2id_oro_workflow_transition_sales_funnel_owner']/a");
+ $this->owner->click();
+ $this->waitForAjax();
+ $this->test->byXpath("//div[@id='select2-drop']/div/input")->value($owner);
+ $this->waitForAjax();
+ $this->assertElementPresent(
+ "//div[@id='select2-drop']//div[contains(., '{$owner}')]",
+ "Owner autocoplete doesn't return search value"
+ );
+ $this->test->byXpath("//div[@id='select2-drop']//div[contains(., '{$owner}')]")->click();
+
+ return $this;
+ }
+
+ public function setLead($lead)
+ {
+ $this->lead = $this->test->byXpath("//div[@id='s2id_oro_workflow_transition_lead']/a");
+ $this->lead->click();
+ $this->waitForAjax();
+ $this->test->byXpath("//div[@id='select2-drop']/div/input")->value($lead);
+ $this->waitForAjax();
+ $this->assertElementPresent(
+ "//div[@id='select2-drop']//div[contains(., '{$lead}')]",
+ "Lead autocoplete doesn't return search value"
+ );
+ $this->test->byXpath("//div[@id='select2-drop']//div[contains(., '{$lead}')]")->click();
+
+ return $this;
+ }
+
+ public function setOpportunity($opportunity)
+ {
+ $this->opportunity = $this->test->byXpath("//div[@id='s2id_oro_workflow_transition_opportunity']/a");
+ $this->opportunity->click();
+ $this->waitForAjax();
+ $this->test->byXpath("//div[@id='select2-drop']/div/input")->value($opportunity);
+ $this->waitForAjax();
+ $this->assertElementPresent(
+ "//div[@id='select2-drop']//div[contains(., '{$opportunity}')]",
+ "Opportunity autocoplete doesn't return search value"
+ );
+ $this->test->byXpath("//div[@id='select2-drop']//div[contains(., '{$opportunity}')]")->click();
+
+ return $this;
+ }
+
+ public function submit()
+ {
+ $this->test->byXpath("//button[@id='save-and-transit']")->click();
+ $this->waitPageToLoad();
+ $this->waitForAjax();
+ return $this;
+ }
+
+ public function edit()
+ {
+ $this->test->byXpath(
+ "//div[@class='pull-left btn-group icons-holder']/a[@title = 'Edit sales activity']"
+ )->click();
+ $this->waitPageToLoad();
+ $this->waitForAjax();
+ return $this;
+ }
+
+ public function delete()
+ {
+ $this->test->byXpath("//div[@class='pull-left btn-group icons-holder']/a[contains(., 'Delete')]")->click();
+ $this->test->byXpath("//div[div[contains(., 'Delete Confirmation')]]//a[text()='Yes, Delete']")->click();
+ $this->waitPageToLoad();
+ $this->waitForAjax();
+ return new SalesActivities($this->test, false);
+ }
+}
diff --git a/src/OroCRM/Bundle/SalesBundle/Tests/Selenium/Pages/Workflow.php b/src/OroCRM/Bundle/SalesBundle/Tests/Selenium/Pages/Workflow.php
index 834410787d3..eac6ffa165b 100644
--- a/src/OroCRM/Bundle/SalesBundle/Tests/Selenium/Pages/Workflow.php
+++ b/src/OroCRM/Bundle/SalesBundle/Tests/Selenium/Pages/Workflow.php
@@ -44,7 +44,7 @@ public function setContact($contact)
public function setAccount($account)
{
- $this->test->byXpath("//div[@id='s2id_oro_workflow_transition_account']/a")->click();
+ $this->test->byXpath("//div[@id='s2id_oro_workflow_transition_new_account']/a")->click();
$this->waitForAjax();
$this->test->byXpath("//div[@id='select2-drop']/div/input")->value($account);
$this->waitForAjax();
@@ -106,7 +106,7 @@ public function setSolution($solution)
public function getSolution()
{
- return $this->solution->value();
+ return $$this->test->byId('oro_workflow_transition_proposed_solution')->value();
}
public function setCloseRevenue($closeRevenue)
@@ -147,7 +147,9 @@ public function getCompanyName()
public function qualify()
{
- $this->test->byXpath("//div[@class='btn-group']/a[@id='transition-b2b_flow_lead-qualify']")->click();
+ $this->test->byXpath(
+ "//div[@class='btn-group']/a[@id='transition-b2b_flow_sales_funnel-qualify']"
+ )->click();
$this->waitPageToLoad();
$this->waitForAjax();
$this->assertElementPresent(
@@ -158,7 +160,31 @@ public function qualify()
public function disqualify()
{
- $this->test->byXpath("//div[@class='btn-group']/a[@id='transition-b2b_flow_lead-cancel']")->click();
+ $this->test->byXpath(
+ "//div[@class='btn-group']/a[@id='transition-b2b_flow_sales_funnel-disqualify']"
+ )->click();
+ $this->waitPageToLoad();
+ $this->waitForAjax();
+ return $this;
+ }
+
+ public function reactivate()
+ {
+ $this->test->byXpath(
+ "//div[@class='btn-group']/a[@id='transition-b2b_flow_sales_funnel-reactivate']"
+ )->click();
+ $this->waitPageToLoad();
+ $this->waitForAjax();
+ return $this;
+ }
+
+ public function reopen()
+ {
+ $this->test->byXpath(
+ "//div[@class='btn-group']/a[@id='transition-b2b_flow_sales_funnel-reopen']"
+ )->click();
+ $this->waitForAjax();
+ $this->test->byXpath("//div[div[contains(., 'Reopen')]]//a[text()='OK']")->click();
$this->waitPageToLoad();
$this->waitForAjax();
return $this;
@@ -166,7 +192,9 @@ public function disqualify()
public function develop()
{
- $this->test->byXpath("//div[@class='btn-group']/a[@id='transition-b2b_flow_sales-develop']")->click();
+ $this->test->byXpath(
+ "//div[@class='btn-group']/a[@id='transition-b2b_flow_sales_funnel-develop']"
+ )->click();
$this->waitPageToLoad();
$this->waitForAjax();
$this->assertElementPresent(
@@ -177,7 +205,9 @@ public function develop()
public function closeAsWon()
{
- $this->test->byXpath("//div[@class='btn-group']/a[@id='transition-b2b_flow_sales-close_as_won']")->click();
+ $this->test->byXpath(
+ "//div[@class='btn-group']/a[@id='transition-b2b_flow_sales_funnel-close_as_won']"
+ )->click();
$this->waitPageToLoad();
$this->waitForAjax();
return $this;
@@ -185,12 +215,20 @@ public function closeAsWon()
public function closeAsLost()
{
- $this->test->byXpath("//div[@class='btn-group']/a[@id='transition-b2b_flow_sales-close_as_lost']")->click();
+ $this->test->byXpath(
+ "//div[@class='btn-group']/a[@id='transition-b2b_flow_sales_funnel-close_as_lost']"
+ )->click();
$this->waitPageToLoad();
$this->waitForAjax();
return $this;
}
+ public function checkStep($step)
+ {
+ $this->assertElementPresent("//div[@class='widget-content']//li[normalize-space(.)='{$step}']");
+ return $this;
+ }
+
public function submit()
{
$this->test->byXpath("//button[normalize-space(text()) = 'Submit']")->click();
diff --git a/src/OroCRM/Bundle/SalesBundle/Tests/Selenium/WorkflowTest.php b/src/OroCRM/Bundle/SalesBundle/Tests/Selenium/WorkflowTest.php
index 856570e1330..f7257de7c70 100644
--- a/src/OroCRM/Bundle/SalesBundle/Tests/Selenium/WorkflowTest.php
+++ b/src/OroCRM/Bundle/SalesBundle/Tests/Selenium/WorkflowTest.php
@@ -21,57 +21,115 @@ class WorkflowTest extends Selenium2TestCase
'region' => 'New York'
);
- protected function setUp()
- {
- $this->markTestIncomplete('Should be fixed after all workflow improvements in scope of CRM-779');
-
- parent::setUp();
- }
-
- public function testLeadWorkflow()
+ public function testLeadWorkflowAsWon()
{
$login = $this->login();
$leadName = $this->createLead($login);
+ $accountName = $this->createAccount($login);
+ $activityname = 'Activity name_' . mt_rand();
- $login->openLeads('OroCRM\Bundle\SalesBundle')
- ->filterBy('Lead name', $leadName)
- ->open(array($leadName))
+ $login->openSalesActivities('OroCRM\Bundle\SalesBundle')
+ ->startFromLead()
+ ->setActivityName($activityname)
+ ->setLead($leadName)
+ ->submit()
->openWorkflow('OroCRM\Bundle\SalesBundle')
+ ->checkStep('New Lead')
->qualify()
+ ->setAccount($accountName)
->submit()
+ ->checkStep('New Opportunity')
->develop()
->setBudget('100')
->setProbability('100')
->setCustomerNeed('Some customer need')
->setSolution('Some solution')
->submit()
+ ->checkStep('Developed Opportunity')
->closeAsWon()
->setCloseRevenue('100')
->submit()
- ->openOpportunity('OroCRM\Bundle\SalesBundle', false)
+ ->checkStep('Won Opportunity')
+ ->openOpportunities('OroCRM\Bundle\SalesBundle')
+ ->filterBy('Opportunity name', $leadName)
+ ->open(array($leadName))
->checkStatus('Won');
- return $leadName;
+ return $activityname;
+ }
+
+ public function testLeadWorkflowAsLost()
+ {
+ $login = $this->login();
+
+ $leadName = $this->createLead($login);
+ $accountName = $this->createAccount($login);
+ $activityname = 'Activity name_' . mt_rand();
+
+ $login->openSalesActivities('OroCRM\Bundle\SalesBundle')
+ ->startFromLead()
+ ->setActivityName($activityname)
+ ->setLead($leadName)
+ ->submit()
+ ->openWorkflow('OroCRM\Bundle\SalesBundle')
+ ->checkStep('New Lead')
+ ->qualify()
+ ->setAccount($accountName)
+ ->submit()
+ ->checkStep('New Opportunity')
+ ->develop()
+ ->setBudget('100')
+ ->setProbability('100')
+ ->setCustomerNeed('Some customer need')
+ ->setSolution('Some solution')
+ ->submit()
+ ->checkStep('Developed Opportunity')
+ ->closeAsLost()
+ ->setCloseReason('Cancelled')
+ ->submit()
+ ->checkStep('Lost Opportunity')
+ ->openOpportunities('OroCRM\Bundle\SalesBundle')
+ ->filterBy('Opportunity name', $leadName)
+ ->open(array($leadName))
+ ->checkStatus('Lost');
}
/**
- * @param $leadName
- * @depends testLeadWorkflow
+ * @param $activityname
+ * @depends testLeadWorkflowAsWon
* @return string
*/
- public function testLeadWorkflowReactivate($leadName)
+ public function testLeadWorkflowReopen($activityname)
{
$login = $this->login();
- $login->openLeads('OroCRM\Bundle\SalesBundle')
- ->filterBy('Lead name', $leadName)
- ->open(array($leadName))
- ->checkStatus('Qualified')
- ->reactivate()
+ $login->openSalesActivities('OroCRM\Bundle\SalesBundle')
+ ->filterBy('Name', $activityname)
+ ->open(array($activityname))
+ ->assertTitle($activityname . ' - Sales Activity - Sales')
+ ->openWorkflow('OroCRM\Bundle\SalesBundle')
+ ->reopen()
+ ->checkStep('New Opportunity');
+ }
+
+ public function testLeadWorkflowReactivate()
+ {
+ $login = $this->login();
+
+ $leadName = $this->createLead($login);
+ $activityname = 'Activity name_' . mt_rand();
+
+ $login->openSalesActivities('OroCRM\Bundle\SalesBundle')
+ ->startFromLead()
+ ->setActivityName($activityname)
+ ->setLead($leadName)
+ ->submit()
->openWorkflow('OroCRM\Bundle\SalesBundle')
+ ->checkStep('New Lead')
->disqualify()
- ->openLead('OroCRM\Bundle\SalesBundle')
- ->checkStatus('Canceled');
+ ->checkStep('Disqualified Lead')
+ ->reactivate()
+ ->checkStep('New Lead');
}
public function testOpportunityWorkflowAsWon()
@@ -79,22 +137,29 @@ public function testOpportunityWorkflowAsWon()
$login = $this->login();
$opportunityName = $this->createOpportunity($login);
+ $activityname = 'Activity name_' . mt_rand();
- $login->openOpportunities('OroCRM\Bundle\SalesBundle')
- ->filterBy('Opportunity name', $opportunityName)
- ->open(array($opportunityName))
+ $login->openSalesActivities('OroCRM\Bundle\SalesBundle')
+ ->startFromOpportunity()
+ ->setActivityName($activityname)
+ ->setOpportunity($opportunityName)
+ ->submit()
->openWorkflow('OroCRM\Bundle\SalesBundle')
+ ->checkStep('New Opportunity')
->develop()
->setBudget('100')
->setProbability('100')
- ->setCustomerNeed('Some customer needs')
+ ->setCustomerNeed('Some customer need')
->setSolution('Some solution')
->submit()
- ->assertTitle("B2B Sales Flow (Develop) - {$opportunityName} - Opportunities")
+ ->checkStep('Developed Opportunity')
->closeAsWon()
->setCloseRevenue('100')
->submit()
- ->openOpportunity('OroCRM\Bundle\SalesBundle', false)
+ ->checkStep('Won Opportunity')
+ ->openOpportunities('OroCRM\Bundle\SalesBundle')
+ ->filterBy('Opportunity name', $opportunityName)
+ ->open(array($opportunityName))
->checkStatus('Won');
}
@@ -103,24 +168,49 @@ public function testOpportunityWorkflowAsLost()
$login = $this->login();
$opportunityName = $this->createOpportunity($login);
+ $activityname = 'Activity name_' . mt_rand();
- $login->openOpportunities('OroCRM\Bundle\SalesBundle')
- ->filterBy('Opportunity name', $opportunityName)
- ->open(array($opportunityName))
- ->checkStatus('In Progress')
+ $login->openSalesActivities('OroCRM\Bundle\SalesBundle')
+ ->startFromOpportunity()
+ ->setActivityName($activityname)
+ ->setOpportunity($opportunityName)
+ ->submit()
->openWorkflow('OroCRM\Bundle\SalesBundle')
+ ->checkStep('New Opportunity')
->develop()
->setBudget('100')
->setProbability('100')
- ->setCustomerNeed('Some customer needs')
+ ->setCustomerNeed('Some customer need')
->setSolution('Some solution')
->submit()
- ->assertTitle("B2B Sales Flow (Develop) - {$opportunityName} - Opportunities")
+ ->checkStep('Developed Opportunity')
->closeAsLost()
->setCloseReason('Cancelled')
->submit()
- ->openOpportunity('OroCRM\Bundle\SalesBundle', false)
+ ->checkStep('Lost Opportunity')
+ ->openOpportunities('OroCRM\Bundle\SalesBundle')
+ ->filterBy('Opportunity name', $opportunityName)
+ ->open(array($opportunityName))
->checkStatus('Lost');
+
+ return $activityname;
+ }
+
+ /**
+ * @param $activityname
+ * @depends testOpportunityWorkflowAsLost
+ * @return string
+ */
+ public function testOpportunityWorkflowReopen($activityname)
+ {
+ $login = $this->login();
+ $login->openSalesActivities('OroCRM\Bundle\SalesBundle')
+ ->filterBy('Name', $activityname)
+ ->open(array($activityname))
+ ->assertTitle($activityname . ' - Sales Activity - Sales')
+ ->openWorkflow('OroCRM\Bundle\SalesBundle')
+ ->reopen()
+ ->checkStep('New Opportunity');
}
/**
diff --git a/src/OroCRM/Bundle/SalesBundle/Tests/Unit/Entity/LeadStatusTest.php b/src/OroCRM/Bundle/SalesBundle/Tests/Unit/Entity/LeadStatusTest.php
new file mode 100644
index 00000000000..94dcff56d09
--- /dev/null
+++ b/src/OroCRM/Bundle/SalesBundle/Tests/Unit/Entity/LeadStatusTest.php
@@ -0,0 +1,21 @@
+assertEquals('test_name', $obj->getName());
+ }
+
+ public function testGetLabel()
+ {
+ $obj = new LeadStatus('test_name');
+ $obj->setLabel('test_label');
+ $this->assertEquals('test_label', $obj->getLabel());
+ }
+}
diff --git a/src/OroCRM/Bundle/SalesBundle/Tests/Unit/Entity/LeadTest.php b/src/OroCRM/Bundle/SalesBundle/Tests/Unit/Entity/LeadTest.php
index f1d5c1cc9b2..2b59c8e14cf 100644
--- a/src/OroCRM/Bundle/SalesBundle/Tests/Unit/Entity/LeadTest.php
+++ b/src/OroCRM/Bundle/SalesBundle/Tests/Unit/Entity/LeadTest.php
@@ -20,8 +20,12 @@ public function testGetSet($property, $value, $expected)
public function getSetDataProvider()
{
$now = new \DateTime('now');
- $user = $this->getMockBuilder('Oro\Bundle\UserBundle\Entity\User');
- $address = $this->getMockBuilder('Oro\Bundle\AddressBundle\Entity\Address');
+ $user = $this->getMockBuilder('Oro\Bundle\UserBundle\Entity\User')
+ ->disableOriginalConstructor()
+ ->getMock();
+ $address = $this->getMockBuilder('Oro\Bundle\AddressBundle\Entity\Address')
+ ->disableOriginalConstructor()
+ ->getMock();
return array(
'namePrefix' => array('namePrefix', 'test', 'test'),
'firstName' => array('firstName', 'test', 'test'),
diff --git a/src/OroCRM/Bundle/SalesBundle/Tests/Unit/Entity/OpportunityCloseReasonStatusTest.php b/src/OroCRM/Bundle/SalesBundle/Tests/Unit/Entity/OpportunityCloseReasonStatusTest.php
new file mode 100644
index 00000000000..100eae2e064
--- /dev/null
+++ b/src/OroCRM/Bundle/SalesBundle/Tests/Unit/Entity/OpportunityCloseReasonStatusTest.php
@@ -0,0 +1,21 @@
+assertEquals('test_name', $obj->getName());
+ }
+
+ public function testGetLabel()
+ {
+ $obj = new OpportunityCloseReason('test_name');
+ $obj->setLabel('test_label');
+ $this->assertEquals('test_label', $obj->getLabel());
+ }
+}
diff --git a/src/OroCRM/Bundle/SalesBundle/Tests/Unit/Entity/OpportunityStatusTest.php b/src/OroCRM/Bundle/SalesBundle/Tests/Unit/Entity/OpportunityStatusTest.php
new file mode 100644
index 00000000000..6239a80df5c
--- /dev/null
+++ b/src/OroCRM/Bundle/SalesBundle/Tests/Unit/Entity/OpportunityStatusTest.php
@@ -0,0 +1,21 @@
+assertEquals('test_name', $obj->getName());
+ }
+
+ public function testGetLabel()
+ {
+ $obj = new OpportunityStatus('test_name');
+ $obj->setLabel('test_label');
+ $this->assertEquals('test_label', $obj->getLabel());
+ }
+}
diff --git a/src/OroCRM/Bundle/SalesBundle/Tests/Unit/Entity/SalesFunnelTest.php b/src/OroCRM/Bundle/SalesBundle/Tests/Unit/Entity/SalesFunnelTest.php
new file mode 100644
index 00000000000..50aea0d6b56
--- /dev/null
+++ b/src/OroCRM/Bundle/SalesBundle/Tests/Unit/Entity/SalesFunnelTest.php
@@ -0,0 +1,73 @@
+assertEquals($expected, call_user_func_array(array($obj, 'get' . ucfirst($property)), array()));
+ }
+
+ public function getSetDataProvider()
+ {
+ $now = new \DateTime('now');
+ $lead = $this->getMockBuilder('OroCRM\Bundle\SalesBundle\Entity\Lead')
+ ->disableOriginalConstructor()
+ ->getMock();
+ $opportunity = $this->getMockBuilder('OroCRM\Bundle\SalesBundle\Entity\Opportunity')
+ ->disableOriginalConstructor()
+ ->getMock();
+ $user = $this->getMockBuilder('Oro\Bundle\UserBundle\Entity\User')
+ ->disableOriginalConstructor()
+ ->getMock();
+ $workflowItem = $this->getMockBuilder('Oro\Bundle\WorkflowBundle\Entity\WorkflowItem')
+ ->disableOriginalConstructor()
+ ->getMock();
+ $workflowStep = $this->getMockBuilder('Oro\Bundle\WorkflowBundle\Entity\WorkflowStep')
+ ->disableOriginalConstructor()
+ ->getMock();
+
+ return array(
+ 'name' => array('name', 'test', 'test'),
+ 'startDate' => array('startDate', $now, $now),
+ 'lead' => array('lead', $lead, $lead),
+ 'opportunity' => array('opportunity', $opportunity, $opportunity),
+ 'owner' => array('owner', $user, $user),
+ 'workflowItem' => array('workflowItem', $workflowItem, $workflowItem),
+ 'workflowStep' => array('workflowStep', $workflowStep, $workflowStep),
+ 'createdAt' => array('createdAt', $now, $now),
+ 'updatedAt' => array('updatedAt', $now, $now),
+ );
+ }
+
+ public function testBeforeSave()
+ {
+ $obj = new SalesFunnel();
+ $this->assertNull($obj->getCreatedAt());
+ $this->assertNull($obj->getUpdatedAt());
+ $obj->beforeSave();
+
+ $this->assertInstanceOf('\DateTime', $obj->getCreatedAt());
+ $this->assertNull($obj->getUpdatedAt());
+ }
+
+ public function testBeforeUpdate()
+ {
+ $obj = new SalesFunnel();
+ $this->assertNull($obj->getCreatedAt());
+ $this->assertNull($obj->getUpdatedAt());
+ $obj->beforeUpdate();
+
+ $this->assertInstanceOf('\DateTime', $obj->getUpdatedAt());
+ $this->assertNull($obj->getCreatedAt());
+ }
+}
diff --git a/src/OroCRM/Bundle/TestFrameworkBundle/Tests/Selenium/Entity/EntityTest.php b/src/OroCRM/Bundle/TestFrameworkBundle/Tests/Selenium/Entity/EntityTest.php
index d1058eeab08..ef9c5c03590 100644
--- a/src/OroCRM/Bundle/TestFrameworkBundle/Tests/Selenium/Entity/EntityTest.php
+++ b/src/OroCRM/Bundle/TestFrameworkBundle/Tests/Selenium/Entity/EntityTest.php
@@ -14,7 +14,7 @@ class EntityTest extends Selenium2TestCase
public function testEditExistEntity()
{
$entityName = 'Account';
- $fieldName = 'Test_field' . mt_rand();
+ $fieldName = 'test_field' . mt_rand();
$login = $this->login();
$login->openConfigEntities('Oro\Bundle\EntityConfigBundle')
->open(array($entityName))
@@ -29,6 +29,6 @@ public function testEditExistEntity()
->openAccounts('OroCRM\Bundle\AccountBundle')
->add()
->openConfigEntity('Oro\Bundle\EntityConfigBundle', false)
- ->checkEntityField($fieldName);
+ ->checkEntityField(ucfirst($fieldName));
}
}