public function testHasOnes() { /** @var DataDifferencerTest_Object $obj1 */ $obj1 = $this->objFromFixture('DataDifferencerTest_Object', 'obj1'); $image1 = $this->objFromFixture('Image', 'image1'); $image2 = $this->objFromFixture('Image', 'image2'); $relobj1 = $this->objFromFixture('DataDifferencerTest_HasOneRelationObject', 'relobj1'); $relobj2 = $this->objFromFixture('DataDifferencerTest_HasOneRelationObject', 'relobj2'); // create a new version $beforeVersion = $obj1->Version; $obj1->ImageID = $image2->ID; $obj1->HasOneRelationID = $relobj2->ID; $obj1->write(); $afterVersion = $obj1->Version; $this->assertNotEquals($beforeVersion, $afterVersion); /** @var DataDifferencerTest_Object $obj1v1 */ $obj1v1 = Versioned::get_version('DataDifferencerTest_Object', $obj1->ID, $beforeVersion); /** @var DataDifferencerTest_Object $obj1v2 */ $obj1v2 = Versioned::get_version('DataDifferencerTest_Object', $obj1->ID, $afterVersion); $differ = new DataDifferencer($obj1v1, $obj1v2); $obj1Diff = $differ->diffedData(); $this->assertContains($image1->Name, $obj1Diff->getField('Image')); $this->assertContains($image2->Name, $obj1Diff->getField('Image')); $this->assertContains('<ins>obj2</ins><del>obj1</del>', str_replace(' ', '', $obj1Diff->getField('HasOneRelationID'))); }
public function testHasOnes() { $obj1 = $this->objFromFixture('DataDifferencerTest_Object', 'obj1'); $image1 = $this->objFromFixture('DataDifferencerTest_MockImage', 'image1'); $image2 = $this->objFromFixture('DataDifferencerTest_MockImage', 'image2'); $relobj1 = $this->objFromFixture('DataDifferencerTest_HasOneRelationObject', 'relobj1'); $relobj2 = $this->objFromFixture('DataDifferencerTest_HasOneRelationObject', 'relobj2'); // in order to ensure the Filename path is correct, append the correct FRAMEWORK_DIR to the start // this is only really necessary to make the test pass when FRAMEWORK_DIR is not "framework" $image1->Filename = FRAMEWORK_DIR . substr($image1->Filename, 9); $image2->Filename = FRAMEWORK_DIR . substr($image2->Filename, 9); $origUpdateFilesystem = Config::inst()->get('File', 'update_filesystem'); // we don't want the filesystem being updated on write, as we're only dealing with mock files Config::inst()->update('File', 'update_filesystem', false); $image1->write(); $image2->write(); Config::inst()->update('File', 'update_filesystem', $origUpdateFilesystem); // create a new version $obj1->ImageID = $image2->ID; $obj1->HasOneRelationID = $relobj2->ID; $obj1->write(); $obj1v1 = Versioned::get_version('DataDifferencerTest_Object', $obj1->ID, $obj1->Version - 1); $obj1v2 = Versioned::get_version('DataDifferencerTest_Object', $obj1->ID, $obj1->Version); $differ = new DataDifferencer($obj1v1, $obj1v2); $obj1Diff = $differ->diffedData(); $this->assertContains($image1->Filename, $obj1Diff->getField('Image')); $this->assertContains($image2->Filename, $obj1Diff->getField('Image')); $this->assertContains('<ins>obj2</ins><del>obj1</del>', str_replace(' ', '', $obj1Diff->getField('HasOneRelationID'))); }
function testHasOnes() { $obj1 = $this->objFromFixture('DataDifferencerTest_Object', 'obj1'); $image1 = $this->objFromFixture('DataDifferencerTest_MockImage', 'image1'); $image2 = $this->objFromFixture('DataDifferencerTest_MockImage', 'image2'); $relobj1 = $this->objFromFixture('DataDifferencerTest_HasOneRelationObject', 'relobj1'); $relobj2 = $this->objFromFixture('DataDifferencerTest_HasOneRelationObject', 'relobj2'); // create a new version $obj1->ImageID = $image2->ID; $obj1->HasOneRelationID = $relobj2->ID; $obj1->write(); $obj1v1 = Versioned::get_version('DataDifferencerTest_Object', $obj1->ID, $obj1->Version - 1); $obj1v2 = Versioned::get_version('DataDifferencerTest_Object', $obj1->ID, $obj1->Version); $differ = new DataDifferencer($obj1v1, $obj1v2); $obj1Diff = $differ->diffedData(); $this->assertContains($image1->Filename, $obj1Diff->getField('Image')); $this->assertContains($image2->Filename, $obj1Diff->getField('Image')); $this->assertContains('<ins>obj2</ins><del>obj1</del>', $obj1Diff->getField('HasOneRelationID')); }
public function getCMSFields($params = null) { Requirements::css(DATACHANGE_PATH . '/css/datachange-tracker.css'); $fields = FieldList::create(ToggleCompositeField::create('Details', 'Details', array(ReadonlyField::create('ChangeType', 'Type of change'), ReadonlyField::create('ClassType', 'Record Class'), ReadonlyField::create('ClassID', 'Record ID'), ReadonlyField::create('ObjectTitle', 'Record Title'), ReadonlyField::create('Created', 'Modification Date'), ReadonlyField::create('Stage', 'Stage'), ReadonlyField::create('User', 'User', $this->getMemberDetails()), ReadonlyField::create('CurrentURL', 'URL'), ReadonlyField::create('Referer', 'Referer'), ReadonlyField::create('RemoteIP', 'Remote IP'), ReadonlyField::create('Agent', 'Agent')))->setStartClosed(false)->addExtraClass('datachange-field'), ToggleCompositeField::create('RawData', 'Raw Data', array(ReadonlyField::create('Before'), ReadonlyField::create('After'), ReadonlyField::create('GetVars'), ReadonlyField::create('PostVars')))->setStartClosed(false)->addExtraClass('datachange-field')); if (strlen($this->Before)) { $before = Object::create($this->ClassType, unserialize($this->Before), true); $after = Object::create($this->ClassType, unserialize($this->After), true); $diff = DataDifferencer::create($before, $after); $diffed = $diff->diffedData(); $diffText = ''; $changedFields = array(); foreach ($diffed->toMap() as $field => $prop) { $changedFields[] = $readOnly = ReadonlyField::create('ChangedField' . $field, $field, $prop); $readOnly->dontEscape = true; $readOnly->addExtraClass('datachange-field'); } $fields->insertBefore(ToggleCompositeField::create('FieldChanges', 'Changed Fields', $changedFields)->setStartClosed(false)->addExtraClass('datachange-field'), 'RawData'); } $fields = $fields->makeReadonly(); return $fields; }
public function getCMSFields($params = null) { Requirements::css(DATACHANGE_PATH . '/css/datachange-tracker.css'); $fields = FieldList::create(ToggleCompositeField::create('Details', 'Details', array(ReadonlyField::create('ChangeType', 'Type of change'), ReadonlyField::create('ClassType', 'Record Class'), ReadonlyField::create('ClassID', 'Record ID'), ReadonlyField::create('ObjectTitle', 'Record Title'), ReadonlyField::create('Created', 'Modification Date'), ReadonlyField::create('Stage', 'Stage'), ReadonlyField::create('User', 'User', $this->getMemberDetails()), ReadonlyField::create('CurrentURL', 'URL'), ReadonlyField::create('Referer', 'Referer'), ReadonlyField::create('RemoteIP', 'Remote IP'), ReadonlyField::create('Agent', 'Agent')))->setStartClosed(false)->addExtraClass('datachange-field'), ToggleCompositeField::create('RawData', 'Raw Data', array(ReadonlyField::create('Before'), ReadonlyField::create('After'), ReadonlyField::create('GetVars'), ReadonlyField::create('PostVars')))->setStartClosed(false)->addExtraClass('datachange-field')); if (strlen($this->Before)) { $before = Object::create($this->ClassType, json_decode($this->Before, true), true); $after = Object::create($this->ClassType, json_decode($this->After, true), true); $diff = DataDifferencer::create($before, $after); // The solr search service injector dependency causes issues with comparison, since it has public variables that are stored in an array. $diff->ignoreFields(array('searchService')); $diffed = $diff->diffedData(); $diffText = ''; $changedFields = array(); foreach ($diffed->toMap() as $field => $prop) { if (is_object($prop)) { continue; } $changedFields[] = $readOnly = ReadonlyField::create('ChangedField' . $field, $field, $prop); $readOnly->dontEscape = true; $readOnly->addExtraClass('datachange-field'); } $fields->insertBefore(ToggleCompositeField::create('FieldChanges', 'Changed Fields', $changedFields)->setStartClosed(false)->addExtraClass('datachange-field'), 'RawData'); } // Flags fields that cannot be rendered with 'forTemplate'. This prevents bugs where // WorkflowService (of AdvancedWorkflow Module) and BlockManager (of Sheadawson/blocks module) get put // into a field and break the page. $fieldsToRemove = array(); foreach ($fields->dataFields() as $field) { $value = $field->Value(); if ($value && is_object($value)) { if ($value instanceof Object && !$value->hasMethod('forTemplate') || !method_exists($value, 'forTemplate')) { $field->setValue('[Missing ' . get_class($value) . '::forTemplate]'); } } } $fields = $fields->makeReadonly(); return $fields; }
/** * Compare two version, and return the diff between them. * @param string $from The version to compare from. * @param string $to The version to compare to. * @return DataObject */ function compareVersions($from, $to) { $fromRecord = Versioned::get_version($this->owner->class, $this->owner->ID, $from); $toRecord = Versioned::get_version($this->owner->class, $this->owner->ID, $to); $diff = new DataDifferencer($fromRecord, $toRecord); return $diff->diffedData(); }
public function ItemEditForm() { Requirements::javascript("orders/javascript/entwine.orders.js"); $form = parent::ItemEditForm(); $fields = $form->Fields(); $actions = $form->Actions(); $record = $this->record; $member = Member::currentUser(); $can_view = $this->record->canView(); $can_edit = $this->record->canEdit(); $can_change_status = $this->record->canChangeStatus(); $can_delete = $this->record->canDelete(); $can_create = $this->record->canCreate(); // First remove the delete button $actions->removeByName("action_doDelete"); // Deal with Estimate objects if ($record->ClassName == "Estimate") { if ($record->ID && $record->AccessKey) { $frontend_url = Controller::join_links(Director::absoluteBaseUrl(), "OrdersFront", "quote", $record->ID, $record->AccessKey); $html = '<a href="' . $frontend_url . '" '; $html .= 'target="_blank" '; $html .= 'class="action ss-ui-button ui-button ui-corner-all open-external" '; $html .= '>' . _t('Orders.ViewQuote', 'View Quote') . '</a>'; $actions->insertAfter(LiteralField::create('openQuote', $html), "action_doSave"); } if ($record->ID && $can_edit) { $actions->insertAfter(FormAction::create('doConvert', _t('Orders.ConvertToOrder', 'Convert To Order'))->setUseButtonTag(true), "action_doSave"); } } // Deal with Order objects if ($record->ClassName == "Order") { // Set our status field as a dropdown (has to be here to // ignore canedit) // Allow users to change status (as long as they have permission) if ($can_edit || $can_change_status) { $status_field = DropdownField::create('Status', null, $record->config()->statuses); // Set default status if we can if (!$record->Status && !$record->config()->default_status) { $status_field->setValue($record->config()->default_status); } else { $status_field->setValue($record->Status); } $fields->replaceField("Status", $status_field); } // Setup order history if (Permission::check(array('COMMERCE_ORDER_HISTORY', 'ADMIN'), 'any', $member)) { $versions = $record->AllVersions(); $first_version = $versions->First(); $curr_version = $first_version ? $versions->First() : null; $message = ""; foreach ($versions as $version) { $i = $version->Version; $name = "History_{$i}"; if ($i > 0) { $frm = Versioned::get_version($record->class, $record->ID, $i - 1); $to = Versioned::get_version($record->class, $record->ID, $i); $diff = new DataDifferencer($frm, $to); if ($version->Author()) { $message = "<p>{$version->Author()->FirstName} ({$version->LastEdited})</p>"; } else { $message = "<p>Unknown ({$version->LastEdited})</p>"; } if ($diff->ChangedFields()->exists()) { $message .= "<ul>"; // Now loop through all changed fields and track as message foreach ($diff->ChangedFields() as $change) { if ($change->Name != "LastEdited") { $message .= "<li>{$change->Title}: {$change->Diff}</li>"; } } $message .= "</ul>"; } $fields->addFieldToTab("Root.History", LiteralField::create($name, "<div class=\"field\">{$message}</div>")); } } } // Is user cannot edit, but can change status, add change // status button if ($record->ID && !$can_edit && $can_change_status) { $actions->push(FormAction::create('doChangeStatus', _t('Orders.Save', 'Save'))->setUseButtonTag(true)->addExtraClass('ss-ui-action-constructive')->setAttribute('data-icon', 'accept')); } if ($record->ID && $record->AccessKey) { $frontend_url = Controller::join_links(Director::absoluteBaseUrl(), "OrdersFront", "invoice", $record->ID, $record->AccessKey); $html = '<a href="' . $frontend_url . '" '; $html .= 'target="_blank" '; $html .= 'class="action ss-ui-button ui-button ui-corner-all open-external" '; $html .= '>' . _t('Orders.ViewInvoice', 'View Invoice') . '</a>'; $link_field = LiteralField::create('openQuote', $html); if ($actions->find("Name", "action_doSave")) { $actions->insertAfter($link_field, "action_doSave"); } if ($actions->find("Name", "action_doChangeStatus")) { $actions->insertAfter($link_field, "action_doChangeStatus"); } } } // Add a duplicate button, either after the save button or // the change status "save" button. if ($record->ID) { $duplicate_button = FormAction::create('doDuplicate', _t('Orders.Duplicate', 'Duplicate'))->setUseButtonTag(true); if ($actions->find("Name", "action_doSave")) { $actions->insertAfter($duplicate_button, "action_doSave"); } if ($actions->find("Name", "action_doChangeStatus")) { $actions->insertAfter($duplicate_button, "action_doChangeStatus"); } } // Finally, if allowed, re-add the delete button (so it is last) if ($record->ID && $can_delete) { $actions->push(FormAction::create('doDelete', _t('GridFieldDetailForm.Delete', 'Delete'))->setUseButtonTag(true)->addExtraClass('ss-ui-action-destructive action-delete')); } // Set our custom template $form->setTemplate("OrdersItemEditForm"); $this->extend("updateItemEditForm", $form); return $form; }
public function getCMSFields() { $fields = parent::getCMSFields(); // Remove defailt item admin $fields->removeByName('Items'); $fields->removeByName('EmailDispatchSent'); $fields->removeByName('PostageID'); $fields->removeByName('PaymentID'); $fields->removeByName('GatewayData'); // Remove Billing Details $fields->removeByName('Address1'); $fields->removeByName('Address2'); $fields->removeByName('City'); $fields->removeByName('PostCode'); $fields->removeByName('Country'); // Remove Delivery Details $fields->removeByName('DeliveryFirstnames'); $fields->removeByName('DeliverySurname'); $fields->removeByName('DeliveryAddress1'); $fields->removeByName('DeliveryAddress2'); $fields->removeByName('DeliveryCity'); $fields->removeByName('DeliveryPostCode'); $fields->removeByName('DeliveryCountry'); // Remove default postage fields $fields->removeByName('PostageType'); $fields->removeByName('PostageCost'); $fields->removeByName('PostageTax'); $fields->addFieldToTab('Root.Main', ReadonlyField::create('OrderNumber', "#"), 'Status'); $fields->addFieldToTab('Root.Main', ReadonlyField::create('Created')); $fields->addFieldToTab('Root.Main', ReadonlyField::create('LastEdited', 'Last time order was saved')); // Structure billing details $billing_fields = ToggleCompositeField::create('BillingDetails', 'Billing Details', array(TextField::create('Address1', 'Address 1'), TextField::create('Address2', 'Address 2'), TextField::create('City', 'City'), TextField::create('PostCode', 'Post Code'), TextField::create('Country', 'Country')))->setHeadingLevel(4); // Structure delivery details $delivery_fields = ToggleCompositeField::create('DeliveryDetails', 'Delivery Details', array(TextField::create('DeliveryFirstnames', 'First Name(s)'), TextField::create('DeliverySurname', 'Surname'), TextField::create('DeliveryAddress1', 'Address 1'), TextField::create('DeliveryAddress2', 'Address 2'), TextField::create('DeliveryCity', 'City'), TextField::create('DeliveryPostCode', 'Post Code'), TextField::create('DeliveryCountry', 'Country')))->setHeadingLevel(4); // Postage details // Structure billing details $postage_fields = ToggleCompositeField::create('Postage', 'Postage Details', array(ReadonlyField::create('PostageType'), ReadonlyField::create('PostageCost'), ReadonlyField::create('PostageTax')))->setHeadingLevel(4); $fields->addFieldToTab('Root.Main', $billing_fields); $fields->addFieldToTab('Root.Main', $delivery_fields); $fields->addFieldToTab('Root.Main', $postage_fields); // Add order items and totals $fields->addFieldToTab('Root.Items', GridField::create('Items', "Order Items", $this->Items(), GridFieldConfig::create()->addComponents(new GridFieldSortableHeader(), new GridFieldDataColumns()))); $fields->addFieldToTab("Root.Items", ReadonlyField::create("SubTotal")->setValue($this->getSubTotal())); $fields->addFieldToTab("Root.Items", ReadonlyField::create("DiscountAmount")->setValue($this->DiscountAmount)); $fields->addFieldToTab("Root.Items", ReadonlyField::create("Tax")->setValue($this->getTaxTotal())); $fields->addFieldToTab("Root.Items", ReadonlyField::create("Total")->setValue($this->getTotal())); $member = Member::currentUser(); if (Permission::check('ADMIN', 'any', $member)) { // Add non-editable payment ID $paymentid_field = TextField::create('PaymentID', "Payment gateway ID number")->setReadonly(true)->performReadonlyTransformation(); $gateway_data = LiteralField::create("FormattedGatewayData", "<strong>Data returned from the payment gateway:</strong><br/><br/>" . str_replace(",", ",<br/>", $this->GatewayData)); $fields->addFieldToTab('Root.Gateway', $paymentid_field); $fields->addFieldToTab("Root.Gateway", $gateway_data); } if (Permission::check(array('COMMERCE_ORDER_HISTORY', 'ADMIN'), 'any', $member)) { // Setup basic history of this order $versions = $this->AllVersions(); $curr_version = $versions->First()->Version; $message = ""; foreach ($versions as $version) { $i = $version->Version; $name = "History_{$i}"; if ($i > 1) { $frm = Versioned::get_version($this->class, $this->ID, $i - 1); $to = Versioned::get_version($this->class, $this->ID, $i); $diff = new DataDifferencer($frm, $to); if ($version->Author()) { $message = "<p>{$version->Author()->FirstName} ({$version->LastEdited})</p>"; } else { $message = "<p>Unknown ({$version->LastEdited})</p>"; } if ($diff->ChangedFields()->exists()) { $message .= "<ul>"; // Now loop through all changed fields and track as message foreach ($diff->ChangedFields() as $change) { if ($change->Name != "LastEdited") { $message .= "<li>{$change->Title}: {$change->Diff}</li>"; } } $message .= "</ul>"; } } $fields->addFieldToTab("Root.History", LiteralField::create($name, "<div class=\"field\">{$message}</div>")); } } $this->extend("updateCMSFields", $fields); return $fields; }