Collection: filter by created_at by local time zone? (or CreatedAtStoreDate) - magento

I have to filter a collection (invoice) by date to get all invoices of one month.
For example: the create_at date of one invoice (in database) is: 2014-04-30 22:27:30
If I filter the collection:
$dateFrom = '2014-04-01 00:00:00';
$dateTo = '2014-04-30 23:59:59';
$invoiceCollection->addAttributeToFilter('created_at', array(
'from' => $dateFrom,
'to' => $dateTo,
));
The invoice with this date will be in the collection.
There exists two kinds of dates:
$invoice->getCreatedAt()
And:
$invoice->getCreatedAtStoreDate()
In this case:
$invoice->getCreatedAt() = 2014-04-30 22:27:30 (UTC/GMT time)
$invoice->getCreatedAtStoreDate() = 2014-05-01 00:27:40 (local timezone)
Under Sales->Invoices "my" invoice will be collect under May. If I use
$invoiceCollection = Mage::getModel('sales/order_invoice')->getCollection();
the invoice is in "April".
So I have to filter my collection by CreatedAtStoreDate - but this is not a database-field.
My question:
How can I filter the order or invoice collection by CreatedAtStoreDate, so that the invoice or order with the date 2014-04-30 22:27:30 will be NOT in my April-Collection but in May?
Thanks for help.

You can use some GET param to define local offset, then add this offset to dates in filter. It will something like this (I didn't test it):
/**
* GET param which allow to set offset between local and server timezone. Server timezone is GMT.
* Examples: add ?gmt=2 in URL for set local time to GMT+2, ?gmt=-5 for GMT-5, etc.
*/
$gmt_offset = (int)Mage::app()->getRequest()->getParam('gmt');
$dateFrom = '2014-04-01 00:00:00';
$dateTo = '2014-04-30 23:59:59';
if($gmt_offset > -13 && $gmt_offset < 15 && $gmt_offset != 0){
$locale = Mage::app()->getLocale()->getLocaleCode();
$date_from = new Zend_Date(strtotime($dateFrom), Zend_Date::TIMESTAMP, $locale);
$date_to = new Zend_Date(strtotime($dateTo), Zend_Date::TIMESTAMP, $locale);
if($gmt_offset > 0){
$date_from->add($gmt_offset, Zend_Date::HOUR);
$date_to->add($gmt_offset, Zend_Date::HOUR);
}else{
$date_from->sub($gmt_offset, Zend_Date::HOUR);
$date_to->sub($gmt_offset, Zend_Date::HOUR);
}
$dateFrom = $date_from->get('YYYY-MM-dd HH:mm:ss');
$dateTo = $date_to->get('YYYY-MM-dd HH:mm:ss');
}
$invoiceCollection->addAttributeToFilter('created_at', array(
'from' => $dateFrom,
'to' => $dateTo,
));

Related

How to get missing dates between 7 latest rows from database?

I want to get 7 latest rows (in order from down to up), for the current week (Sunday to Saturday), for the current logged in user.
To do this, I used this one method:
Carbon::setWeekStartsAt(Carbon::SUNDAY);
Carbon::setWeekEndsAt(Carbon::SATURDAY);
$strikes = UserStrike::where('user_id', $user)->whereBetween('created_at', [Carbon::now()->startOfWeek(), Carbon::now()->endOfWeek()])->latest()->take(7)->get();
$strikes = $strikes->reverse(); //to order the list from DESC to ASC
But the problem with this method is that it doesn't get any missing days.
So if there are data like this for the current week (2020-05-12 is missing):
created_at: 2020-05-10
created_at: 2020-05-11
created_at: 2020-05-13
Then for that one day which is missing, there should be a null in array. Something like this:
$days = ["Sun", "Mon", null, "Wed"];
I'm having hard time to find a way to replace missing day with a null in array.
If anyone here can help me with this problem please leave your comment. Thank you in advance.
You can take data from DB and then create array by iterating on DateTimeInterval(). I don't know Laravel and Carbon well but it could be something like this:
Carbon::setWeekStartsAt(Carbon::SUNDAY);
Carbon::setWeekEndsAt(Carbon::SATURDAY);
$start = Carbon::now()->startOfWeek();
$end = Carbon::now()->endOfWeek();
$strikes = UserStrike::where('user_id', $user)
->whereBetween(
'created_at',
[$start, $end]
)
->latest()
->take(7)
->get();
$strikes = $strikes->reverse();
$timePeriod = new DatePeriod(
$start,
new DateInterval('P1D'),
$end
);
$days = [];
for ($i = 0; $i < count($timePeriod) $i++) {
$days[$i] = null;
foreach ($strikes as $strike) {
if ($strike->created_at->format('Y-m-d') == $timePeriod[$i]->format('Y-m-d') {
$days[$i] = $strike->created_at->format('Y-m-d');
break;
}
}
}

Magento get manufacturer labels ONLY for a particular store

I'm trying to get manufacturer labels only for a particular store, but it's not working and I always get all manufacturers (of all stores). Any ideas? Thats my code:
$entityTypeIdentifier = 'catalog_product';
$attributeCode = 'manufacturer';
$storeId = 2;
$attributeModel = Mage::getModel('eav/entity_attribute');
$attributeId =
$attributeModel->getIdByCode($entityTypeIdentifier,$attributeCode);
$attribute = $attributeModel->load($attributeId);
$attribute->setStoreId( $storeId );
$attributeOptionsModel = Mage::getModel('eav/entity_attribute_source_table');
$attributeTable = $attributeOptionsModel->setAttribute($attribute);
$options = $attributeOptionsModel->getAllOptions(false);
echo '<pre>';
print_r($options);
$attribute->setStoreId( $storeId ); is ignored and thats the result:
Array
(
[0] => Array
(
[value] => 204
[label] => 3M ESPAÑA
)
.
.
.
Thats eav_attribute_option_value table:
value_id
option_id
store_id
value
1263
204
0
3M ESPAÑA
1264
204
1
3M ESPAÑA
In getAllOptions function of Mage_Eav_Model_Entity_Attribute_Source_Table class, an option's value will be returned whether it has store specific value or not.
For example, if you have 100 options for an attribute and store #2 has values for 20 of them, option model will return 100 options whether you setStoreId(2) or not. If you set store id, model will return 20 of them in store #2 value, other 80 options in default value.
But if you need an answer to get only that 20 values, here you are my friend:
$entityTypeIdentifier = 'catalog_product';
$attributeCode = 'manufacturer';
$storeId = 2;
$resource = Mage::getSingleton('core/resource');
$connection = $resource->getConnection('read');
$query = $connection->select()
->from(array('e' => $resource->getTableName('eav/attribute')), array())
->joinLeft(array(
'f' => $resource->getTableName('eav/entity_type')),
"e.entity_type_id = f.entity_type_id AND f.entity_type_code = '$entityTypeIdentifier'",
array()
)
->joinLeft(array(
'g' => $resource->getTableName('eav/attribute_option')),
'e.attribute_id = g.attribute_id',
array()
)
->joinRight(
array('h' => $resource->getTableName('eav/attribute_option_value')),
"g.option_id = h.option_id AND h.store_id = $storeId",
array('h.option_id', 'h.value')
)
->where('e.attribute_code = ?', $attributeCode);
$options = $connection->fetchAssoc($query);
echo '<pre>';
print_r($options);

How to use date helper in CodeIgniter to find time conflict?

I have a database table
TABLE subject_loads
id (int)
subject_name (varchar)
time_start (time)
time_end (time)
time_diff (decimal)
When I save it on database, it will first check whether the time is not conflicting from the other time already inputed. If it's okay, then compute the time_start and time_end to give me a difference between the two.
Example, 7:30 AM - 8:30 AM is already in database, when i input 8:00 AM - 9:00 AM it will say "conflicting with the other time". Only I can input before 7:30 AM or after 8:30 AM that doesn't overlap from 7:30 AM - 8:30 AM.
Can someone help on how to do this?
First you need to check if overlapping values (compared to new value) already exist. You will do that with:
$query = $this->db->get_where('subject_loads', array('time_start >= ' => $time_start, 'time_end <= ' => $time_end));
if((int)$query->num_rows() > 0)
{
//similar values exist
}
else
{
//you are free to insert values
}
Second part of issue:
$hm1 = "2:12 AM";
$hm2 = "4:41 PM";
$e = conv($hm2) - conv($hm1);
echo $e;
function conv($time)
{
$expl_time = explode(' ', $time);
$t = explode(":", $expl_time[0]);
if ($expl_time[1] == 'PM' || $expl_time[1] == 'pm')
{
$t[0] += 12;
}
return ($t[0] + round($t[1]/60, 1, PHP_ROUND_HALF_UP));
}

Catalog Price Rules applied to special_price

First question on stackoverflow...i am excited :)
Currently magento is using the special price if its lower than the applied catalog price rule. If the catalog price rule makes the product cheaper than the special price, then the catalog price rule defines the shop price.
I am looking for an elegant way to make catalog price rules be applied
to the special price (additionally). Maybe there is some store config for it? Maybe
there is some neat observer way?
Thank you so much!
Works up to current Magento 1.9.3.10. Just tested it in a project after update. Josef tried another approach which might work as well.
I am sad to say, I solved my first real stackoverflow question for my own:
Goto Mage_CatalogRule_Model_Resource_Rule
Goto method _getRuleProductsStmt
Add this to the initial select of the method before the first original ->from:
$select->from(null, array('default_price' => new Zend_Db_Expr("CASE
WHEN pp_default_special.value THEN pp_default_special.value ELSE
pp_default_normal.value END")));
Add this after the first join() has happened
$specialPriceAttr = Mage::getSingleton('eav/config')
->getAttribute(Mage_Catalog_Model_Product::ENTITY, 'special_price');
$specialPriceTable = $specialPriceAttr->getBackend()->getTable();
$specialPriceAttributeId= $specialPriceAttr->getId();
$joinCondition2 = '%1$s.entity_id=rp.product_id AND (%1$s.attribute_id=' . $specialPriceAttributeId . ')
AND %1$s.store_id=%2$s';
$select->join(
array('pp_default_special'=>$specialPriceTable),
sprintf($joinCondition2, 'pp_default_special', Mage_Core_Model_App::ADMIN_STORE_ID), null
);
How it works:
When a catalog price rule is applied (via backend or cron) the db table catalogrule_product_price is populated. The above SQL magic joins the special_price (if exists) to the resultset as column default_value, if no special_price is found the regular price gets joined.
The result has been checked and is working.
Have fun! And dont hack the core!
There seem to be some changes in newer Magento releases!
For 1.9 i had to:
copy app/code/core/Mage/CatalogRule/Model/Action/Index/Refresh.php to app/code/local/Mage/CatalogRule/Model/Action/Index/Refresh.php
Change _prepareTemporarySelect.
I post the function in full here. Joins for special_price are added and then the price added to the selection of the price field. It still prefers group prices, becuas I never use them, but that can be changed easily!
protected
function _prepareTemporarySelect(Mage_Core_Model_Website $website)
{
/** #var $catalogFlatHelper Mage_Catalog_Helper_Product_Flat */
$catalogFlatHelper = $this->_factory->getHelper('catalog/product_flat');
/** #var $eavConfig Mage_Eav_Model_Config */
$eavConfig = $this->_factory->getSingleton('eav/config');
$priceAttribute = $eavConfig->getAttribute(Mage_Catalog_Model_Product::ENTITY, 'price');
$specialPriceAttr = Mage::getSingleton('eav/config')->getAttribute(Mage_Catalog_Model_Product::ENTITY, 'special_price');
$specialPriceTable = $specialPriceAttr->getBackend()->getTable();
$specialPriceAttributeId = $specialPriceAttr->getId();
$select = $this->_connection->select()->from(array(
'rp' => $this->_resource->getTable('catalogrule/rule_product')
) , array())->joinInner(array(
'r' => $this->_resource->getTable('catalogrule/rule')
) , 'r.rule_id = rp.rule_id', array())->where('rp.website_id = ?', $website->getId())->order(array(
'rp.product_id',
'rp.customer_group_id',
'rp.sort_order',
'rp.rule_product_id'
))->joinLeft(array(
'pg' => $this->_resource->getTable('catalog/product_attribute_group_price')
) , 'pg.entity_id = rp.product_id AND pg.customer_group_id = rp.customer_group_id' . ' AND pg.website_id = rp.website_id', array())->joinLeft(array(
'pgd' => $this->_resource->getTable('catalog/product_attribute_group_price')
) , 'pgd.entity_id = rp.product_id AND pgd.customer_group_id = rp.customer_group_id' . ' AND pgd.website_id = 0', array());
$storeId = $website->getDefaultStore()->getId();
if ($catalogFlatHelper->isEnabled() && $storeId && $catalogFlatHelper->isBuilt($storeId))
{
$select->joinInner(array(
'p' => $this->_resource->getTable('catalog/product_flat') . '_' . $storeId
) , 'p.entity_id = rp.product_id', array());
$priceColumn = $this->_connection->getIfNullSql($this->_connection->getIfNullSql('pg.value', 'pgd.value') , $this->_connection->getIfNullSql('p.special_price', 'p.price'));
}
else
{
$select->joinInner(array(
'pd' => $this->_resource->getTable(array(
'catalog/product',
$priceAttribute->getBackendType()
))
) , 'pd.entity_id = rp.product_id AND pd.store_id = 0 AND pd.attribute_id = ' . $priceAttribute->getId() , array())->joinLeft(array(
'pspd' => $specialPriceTable
) , 'pspd.entity_id = rp.product_id AND (pspd.attribute_id=' . $specialPriceAttributeId . ')' . 'AND pspd.store_id = 0', array())->joinLeft(array(
'p' => $this->_resource->getTable(array(
'catalog/product',
$priceAttribute->getBackendType()
))
) , 'p.entity_id = rp.product_id AND p.store_id = ' . $storeId . ' AND p.attribute_id = pd.attribute_id', array())->joinLeft(array(
'psp' => $specialPriceTable
) , 'psp.entity_id = rp.product_id AND (psp.attribute_id=' . $specialPriceAttributeId . ')' . 'AND psp.store_id = ' . $storeId, array());
$priceColumn = $this->_connection->getIfNullSql($this->_connection->getIfNullSql('pg.value', 'pgd.value') , $this->_connection->getIfNullSql('psp.value', $this->_connection->getIfNullSql('pspd.value', $this->_connection->getIfNullSql('p.value', 'pd.value'))));
}
$select->columns(array(
'grouped_id' => $this->_connection->getConcatSql(array(
'rp.product_id',
'rp.customer_group_id'
) , '-') ,
'product_id' => 'rp.product_id',
'customer_group_id' => 'rp.customer_group_id',
'from_date' => 'r.from_date',
'to_date' => 'r.to_date',
'action_amount' => 'rp.action_amount',
'action_operator' => 'rp.action_operator',
'action_stop' => 'rp.action_stop',
'sort_order' => 'rp.sort_order',
'price' => $priceColumn,
'rule_product_id' => 'rp.rule_product_id',
'from_time' => 'rp.from_time',
'to_time' => 'rp.to_time'
));
return $select;
}
I fixed it in another way. It was just easy to put into the price field for example 100 and then into special price field 90 when there was 10% discount on product page but now I removed special price from product page and just created catalog price rule 10% discount to that product(s) and now other rules also work:)

Timepicker that removes times as they're selected (ajax)

I'm building a booking form for a moving business that uses a calendar combined with a start and end time. I built the timepicker with Formidable Pro, and it allows me to check "unique" on time fields which automatically removes them on the selected date. However it doesn't automatically remove the times from within the range between start and end times (ie: if someone chooses to rent a truck from 1am-3am I need 1am,2am,and 3am to be removed from future options but right now it only removes 1am and 3am) . I need to write ajax to remove the in-between times from the options. I'm not sure where to begin. This is the current ajax_time_ options function. Any push in the right direction would be appreciated.
function ajax_time_options(){
global $frmpro_settings, $frmdb, $wpdb;
//posted vars = $time_field, $date_field, $step, $start, $end, $date, $clock
extract($_POST);
$time_key = str_replace('field_', '', $time_field);
$date_key = str_replace('field_', '', $date_field);
if (!preg_match('/^\d{4}-\d{2}-\d{2}$/', trim($date)))
$date = FrmProAppHelper::convert_date($date, $frmpro_settings->date_format, 'Y-m-d');
$date_entries = FrmEntryMeta::getEntryIds("fi.field_key='$date_key' and meta_value='$date'");
$opts = array('' => '');
$time = strtotime($start);
$end = strtotime($end);
$step = explode(':', $step);
$step = (isset($step[1])) ? ($step[0] * 3600 + $step[1] * 60) : ($step[0] * 60);
$format = ($clock) ? 'H:i' : 'h:i A';
while($time <= $end){
$opts[date($format, $time)] = date($format, $time);
$time += $step;
}
if($date_entries and !empty($date_entries)){
$used_times = $wpdb->get_col("SELECT meta_value FROM $frmdb->entry_metas it LEFT JOIN $frmdb->fields fi ON (it.field_id = fi.id) WHERE fi.field_key='$time_key' and it.item_id in (". implode(',', $date_entries).")");
if($used_times and !empty($used_times)){
$number_allowed = apply_filters('frm_allowed_time_count', 1, $time_key, $date_key);
$count = array();
foreach($used_times as $used){
if(!isset($opts[$used]))
continue;
if(!isset($count[$used]))
$count[$used] = 0;
$count[$used]++;
if((int)$count[$used] >= $number_allowed)
unset($opts[$used]);
}
unset($count);
}
}
echo json_encode($opts);
die();
}

Resources