OK, been searching this everywhere, and can't come up with anything... we are externally populating tracking numbers in Magento Community 1.7.0.2 via a sync program from Dydacomp's Mail order Manager software... - it closes the order in Magento and adds a tracking number, but does not trigger the send tracking email function in mage. - I have researched, and seen that there are observers, etc. which appear maybe to be able to do this, but after 20 hours scouring every blog I can find, etc. cannot come up with anything that works!
This link seems to be REALLY in the right direction... but where to put this block of code? I've tried putting it in all kinds of places and none works:
Programmaticly send email when shipping tracking number is set
Any help would be tremendously appreciated.
I developed something similar. I created a module activated by cron (once a day) that checks the last orders that have 'delivered' (complete status).
To run a function in your cron magento module, add to your config.xml
<crontab>
<jobs>
<myModule_myFunction>
<schedule><cron_expr>*/60 * * * *</cron_expr></schedule>
<run><model>emailtracker/cron::myFunction</model></run>
</myModule_myFunction>
</jobs>
</crontab>
For the order to have supplies you can use the following code snippet
$orders = Mage::getModel('sales/order')->getCollection()
->addFieldToFilter('status', 'complete')
->addAttributeToFilter('created_at', array('gteq' => $dataForFilter));
Note that the collection of orders that I created, I make filter by date to avoid retrieving all orders already made.
With my collection of recent and complete orders that are possible candidates to receive a tracking email delivery, I can actually work with the orders that are important.
I created a foreach to run in my collection and within that loop, retrieve the tracking number.
foreach($orders as $order) {
$trackings = Mage::getResourceModel('sales/order_shipment_track_collection')
->setOrderFilter($order)
->getData();
for($i=0;$i<count($trackings);$i++) {
$trackingNumber = $trackings[$i]['track_number'];
//Make your php magic here
}
}
From this point, you can work this information the way you want. You can create a function that checks the status of tracking number via API and its delivery service sends an email, or you can imagine.
Important: Remember to check if your magento cron is active.
Note: I did it in Magento 1.6.1.0
Related
I'm working on a rather simple script which should handle new values in the spreadsheet and then send emails to specified addresses. And I faced with the problem. My code is listed below:
function onEdit(e) {
//part of the code for checking e.range to process only updated values
sendEmail();
}
function sendEmail() {
// arguments are missed only for demo
GmailApp.sendEmail();
}
While I'm using "simple trigger", my function "sendEmail()" works only if I start it from script editor. I allowed sending emails on behalf of my at first time and then function works fine. But if I'm changing the value in the spreadsheet - function "onEdit(e)" processes new data but function "sendEmail()" does nothing.
I partly solved this problem by using project's triggers from "current project's triggers" menu. In that case, function "sendEmail()" works properly, but I have no access to the information about update.
For my purposes I could use just second way and find new values "manually" every time, but I wish to optimize this work.
So, my questions are:
Is the process I described above proper or I made a mistake
anywhere?
If process proper, is where a way to combine both cases?
Thanks!
You correctly understood that (as the docs say) simple triggers cannot send an email, because they run without authorization. An installable trigger, created via Resources menu, can: it has the same rights as the user who created the trigger. If it is set to fire on edit, it will get the same type of event object as a simple trigger does.
So, a minimal example would be like this, set to run "on edit":
function sendMail(e) {
MailApp.sendEmail('user#gmail.com', 'sheet edited', JSON.stringify(e));
}
It emails the whole event object in JSON format.
Aside: if your script only needs to send email but not read it, use MailApp instead of GmailApp to keep the scope of permissions more narrow.
How do I get the top 400 (or more) lists for apps from iTunes? I need the top paid, free, and grossing lists for each category and overall.
I know the rss feed exists, at https://rss.itunes.apple.com/ but that only gives you the top 200. Yet sites like AppFigures and AppAnnie have lists of the top 400 or 500, and apps in the app store will show you the top 400.
I tried the EPF feed, the popularity table only has twenty rows on it, and from other forums it looks like that feed has been unavailable for months, and it doesn't update as often as these other sites seem to anyway.
I am looking for a solution directly from Apple, not via a third party. I am 99% certain that Apple provides this data hourly, but I do not know the endpoint.
Update 12 October 2015: According to Apple Developer Support as of 9th October 2015 the issue has been resolved.
RSS feeds are indeed currently capped at 200 results (although they have been set to max 400 in the past),
Regarding the EPF relational - some services (e.g. Chomp) have relied on it in the past. I'm not sure about its current status, but if you've tried to use it make sure you get the full weekly release (which size-wise must be in the range of over 5 GBs), not just an increment release. Maybe this is the reason you get just a few rows?
Currently I don't know of other ways to get this information from Apple directly. You may try a free service from f6s or use an API provided by another paid service.
Update - Apple feedback received:
This is an interesting topic for me, so I contacted Apple yesterday and asked them is there any way to retrieve this data directly from them. This morning I received feedback on the availability of chart data from the iTunes Affiliate team at Apple. They confirmed the limitations of the RSS feed and also said the following on the EPF question:
If you are an affiliate, you could look into the EPF Relational to develop your own search results.
The EPF is a multiple-gigabyte download of the complete set of
metadata from the iTunes Store, App Store, and Mac App Store. EPF is
available for affiliates to fully incorporate aspects of the iTunes
and App Store catalogs into a website or app. This tool is only for
tech-savvy affiliates, and knowledge of relational databases setup is
required. Apple will not provide technical support for setting up or
maintaining this tool.
EPF access is only available for approved Affiliate Program
publishers. More information regarding the EPF can be found on the
Enterprise Partner Feed documentation page. Review the documentation
found there, and if you would then like access to the EPF, provide the
following information: ...
Upon further investigation of the ERPF technical documentation I found out that one of the tables in the database contains the top 1000 applications by genre:
So, you should first import the data in your own database, starting from a weekly (multi-gigabyte) release, and then apply any daily (multi-megabyte) updates available since the weekly release. According to Apple the difference between the two is:
Feed Modes
iTunes generates the EPF data in two modes:
full mode
incremental mode
The full export is generated weekly and
contains a complete snapshot of iTunes metadata as of the day of
generation. The incremental export is generated daily and contains
records that have been added or modified since the last full export.
The incremental exports are located relative to the full export on
which they are based.
Provided you've imported the data in a relational database, you should be able to get the needed data with a simple SELECT statement similar to this one:
SELECT application.title, applicationpopularityper_genre.application_rank
FROM applicationpopularityper_genre
JOIN application
ON application.application_id = applicationpopularityper_genre.application_id
WHERE applicationpopularityper_genre.genreid = XX
ORDER BY applicationpopularityper_genre.application_rank ASC;
Regarding hourly updates - by looking at the relational structure, I see that an export_date column is available. You should check if you get multiple dates for each application when executing the select above - if you do, you have data with finer granularity than a day. If not (which is more probable), and this is a dealbreaker for you, you should look at using the services of Appannie and others that I already proposed, that enrich this data with the data they get from developers via itunes connect. If you want the information free, you can try to scrape from Appannie (there are some free tools that do this, but you should know that this may not be very reliable in the long term, so you may be better off paying);
Update 2:
iTunes Affiliate Team confirmed that they are aware of the issue with this table.
Hope this answers your question.
Here's how you do it.... you can hit a URL as follows and supply an iOS5 user agent.
_IOS_DEEP_RANK_URL_BASE = 'https://itunes.apple.com/WebObjects/MZStore.woa/wa/topChartFragmentData?genreId=%s&popId=%s&pageNumbers=%d&pageSize=%d'
_IOS_DEEP_RANK_USERAGENT = 'iTunes-iPad/5.1.1 (64GB; dt:28)'
You need to set the store front too, based on what country you want.
"X-Apple-Store-Front: 143441-1,9"
Would scraping data from AppAnnie be fine?
Used phantomjs and casperjs to scrape top 500 of free, paid and grossing.
Install phantomjs and casperjs in your system
In terminal: casperjs appAnnieTop500Scraper.js
Sample Output
Free Apps
500 apps found:
// not shown: app names in json array format
// json array on file: freeTop500.json
Paid Apps
500 apps found:
// not shown: app names in json array format
// json array on file: paidTop500.json
Grossing Apps
500 apps found:
// not shown: app names in json array format
// json array on file: grossingTop500.json
appAnnieTop500Scraper.js
var free = [];
var paid = [];
var grossing = [];
var FREE_COLUMN_INDEX = 1;
var PAID_COLUMN_INDEX = 2;
var GROSSING_COLUMN_INDEX = 3;
var fs = require('fs');
var casper = require('casper').create();
casper.on("click", function() {
this.echo();
});
casper.on("page.error", function() {
this.echo();
});
function getAppListScraper(columnIndex) {
var selector = document.querySelectorAll('tbody#storestats-top-table tr td:nth-child(' + columnIndex + ') div.item-info div.main-info span.title-info');
return Array.prototype.map.call(selector, function(e) {
return e.getAttribute('title');
});
}
function printToConsole(casper, appList) {
casper.echo(appList.length + ' apps found:');
casper.echo(JSON.stringify(appList));
}
function writeToFile(fileName, content) {
fs.write(fileName, content, 'w');
}
casper.start('https://www.appannie.com/apps/ios/top/?device=iphone', function() {
// click load all button to load 500 apps list
this.click('div#load-more-box span.btn-load p a.load-all');
// wait 5000ms for the apps list to load then scrape it
this.wait(5000, function() {
free = this.evaluate(getAppListScraper, FREE_COLUMN_INDEX);
paid = this.evaluate(getAppListScraper, PAID_COLUMN_INDEX);
grossing = this.evaluate(getAppListScraper, GROSSING_COLUMN_INDEX);
});
});
casper.run(function() {
this.echo('Free Apps');
printToConsole(this, free);
writeToFile("freeTop500.json", JSON.stringify(free));
this.echo('Paid Apps');
printToConsole(this, paid);
writeToFile("paidTop500.json", JSON.stringify(paid));
this.echo('Grossing Apps');
printToConsole(this, grossing);
writeToFile("grossingTop500.json", JSON.stringify(grossing));
this.exit();
});
I know this is an old question, but I recently was faced with the same problem.
After joining the dots from many sites, my solution goes like this:
You will need this list for the genres:
https://affiliate.itunes.apple.com/resources/documentation/genre-mapping/
And this list for the country codes:
https://affiliate.itunes.apple.com/resources/documentation/linking-to-the-itunes-music-store/#Legacy
This link gives you a basic RSS overview and generator, but misses so much:
https://rss.itunes.apple.com/en-us
The next are examples I managed to piece together:
Top 100 Christian & Gospel
https://itunes.apple.com/au/rss/topsongs/genre=22/explicit=true/limit=100/xml
Or, the same one with JSON results
https://itunes.apple.com/au/rss/topsongs/genre=22/explicit=true/limit=100/json
Or, without the explicit songs:
https://itunes.apple.com/au/rss/topsongs/genre=22/limit=100/json
Top 100 CCM
https://itunes.apple.com/au/rss/topalbums/genre=1094/explicit=true/limit=100/xml
Just change the genre id, and the country code.
https://itunes.apple.com/{country code}/rss/topalbums/genre={genre code}/explicit=true/limit=100/xml
I have a small form that my colleagues and I often fill out that can be seen here, with source code (view-only) here. The spreadsheet that this form posts to can be seen (view-only) here.
Basically, the apps script is solely for preventing my coworkers from having to scroll through thousands of rows of a spreadsheet (this is also used for our film collection) to check in/out inventory. It will also, soon, post detailed history of the checkout in an audit spreadsheet.
I have attempted, with no success, to clear the values of the text fields after the data has been posted to the spreadsheet. What I essentially want to do is restart the GUI so that the fields are once again blank.
I have tried accessing the text fields by id but the return type is a Generic widget, which I of course can't do anything with. And since control is passed to the handler functions, the text fields can't be accessed, or at least I can't figure out how (and I looked through the documentation and online solutions for hours last night).
So the question: how can I erase/clear the values of the text fields in the GUI after values have been posted to the spreadsheet? (return from handler function to access text fields again, or restart the GUI?
I can accomplish restarting the script runs on a spreadsheet, but I have not been able to do this when it is embedded in a Google site.
The getElementById('xxxxx').setText('') approach was the right way to do it. but the way you tried to test it doesn't work... the new value would only be available in the next handler call.
/*
This function only has the desired effect if it is called within the handler
function (not within a nested function in the handler function).
*/
function restartGUI() {
var gui = UiApp.getActiveApplication();
gui.getElementById('equipmentIDField1').setText('');
gui.getElementById('equipmentIDField2').setText('');
gui.getElementById('equipmentIDField3').setText('');
gui.getElementById('studentLastNameField').setText('');
gui.getElementById('labasstLastNameField').setText('');
return gui;
}
This is my 1st question on this forum... So, please, be indulgent !
I'm using TYPO3 4.7.11 (PHP 5.3.3) with extension direct_mail 3.1.1 for the intranet site of a non-profit firm.
My problem (maybe connected to Bug #51583 : http://forge.typo3.org/issues/51583) is that, after numerous tests and attempts, it seems impossible to have an updated version of a page saved as draft for newsletter in an automatic scheduler driven way : the same newsletter is produced with the same informations that were already there on the day it was first created and saved.
The specific page used for newsletter includes a content element 'Menu/Sitemap' with 'Recently updated pages' as 'Menu type'. It has been saved as 'draft (for recurring sendings)' in Direct Mail.
The scheduler contains these 2 tasks with recurring type :
- Direct Mail: Create Mail from Draft (direct_mail)
- Direct Mail: Mailing Queue (direct_mail)
Note : the manual way is fully functional and the newsletter produced is really updated. Same with option "Testmail - Simple" !
So, my problem seems to be linked to the automatic scheduled mailing ! It looks as if the newsletter draft has turned into a freezed snapshot of a specific moment and that Typo3 is unable to update/recalculate this page when invoked in scheduler mode.
On the web, I saw reported problems that could be related like "When mails get sent via the scheduler the same subject is used for all sendings ( https://review.typo3.org/21313 )" and "Adding hooks when sending direct mails via scheduler ( forge.typo3.org/issues/48994 )", but these issues seem to be fixed with direct_mail 3.1.1 version.
I made these observations and, in my opinion, there is some relevancy :
1.There is no domain proposed in the 'Domain of internal links' drop-down list in 'Set default values for mail content fetching options' in Direct Mailer, and yet I have a single record in sys_domain table with a domain name (with no protocol and no final slash). Is there a reason why this record is not considered good, or isn't it the right table ? (uid=3, pid, tstamp, crdate, cruser_id, hidden, sorting, prepend_params and forced=0, redirectHttpStatusCode=301, domain_name=site.subdomain.domain, redirectTo=)
2.In the Typo 3 Log, I get this systematic error message for user _cli_scheduler#LIVE :
Core: Error handler (BE): PHP Warning: Invalid argument supplied for
foreach() in
...typo3conf/ext/direct_mail/Classes/Scheduler/MailFromDraft.php line
125.
The concerned part of MailFromDraft.php is this function : initializeHookObjects
...
/*
* Initializes hook objects for this class
*
* #return void
*/
function initializeHookObjects() {
foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['direct_mail']['mailFromDraft'] as $hookObj) {
$hookObjectInstance = t3lib_div::getUserObj($hookObj);
if (is_object($hookObjectInstance) && ($hookObjectInstance instanceof x_directmail_Scheduler_MailFromDraftHook)) {
$this->hookObjects[] = $hookObjectInstance;
}
}
}
...
I'm not sure of understanding very clearly the origin and the use of the hook Object... (in spite of this interesting article by Robert Lemke : typo3.org/documentation/article/how-to-use-existing-hooks-in-your-own-extension/ )
3.Nothing like the apparently requested GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['direct_mail']['mailFromDraft'] seems to exist in TYPO3_CONF_VARS (Global configuration).
Can anybody give me an advice or a clue about what's going on and why I can't get a weekly updated newsletter with the scheduler ? I feel a bit confused !
Thanks in advance for any suggestion or solution (if a miracle is possible).
Greetings.
P-H SILLIAU
I've read about this issue before, but couldn't remember where.
Googling "direct_mail draft (for recurring sendings)" helped.
Try this bug: http://forge.typo3.org/issues/4421
User Markus says:
Things work fine, when you set a domain-record in your system and
select it in the direct_mail settings!
If you don't have a domain-record and specify it in the direct_mail
setup you're able to send normal newsletters, but if you try the
draft-functionality it won't work because the getUrlBase function in
class.tx_directmail_static.php returns an unsuable URL to the System
so it can't use the fetchHTML($file) and quits - therefore not
replacing the old draft contents created when starting the first time.
I don't really get why this works the first time you set up the draft
though....
So setting up the domain-record is a work-around that works.
I hope it does!
Probably, you will find more related topics.
Else, workarounds would be
re-considering the task. As it's a NPO intranet, maybe requirements are not that required suddenly, if asked again :-)
setting up a custom notification tool that only does that precise job.
To put an end to this problem, after many attempts (and informations gleaned from the internet), here is the solution we finally used in our specific case to make the newsletter work :
1st. We created a record in table sys_domain. This was a recurrent instruction in the manual and the forums, and it was IMHO legitimate.
Important : note that the redirectTo field had to remain empty, due to global malfunction of the site if filled (whatever we put in it like /, /var/www/sitename, ...)
2nd. All images, CSS, JS included in template had to be hardcoded (i.e. http ://site/fileamin/images/xxx.png for instance). If we didn't do that, the result would have been an abort in the production of the newletter : Not Found... Maybe, by digging a bit deeper, should we be able to find a parameter we forgot or neglected in some way to solve this issue...
3rd. In the newsletter template TS setup, we added these 2 parameters :
mod.web_modules.dmail.use_domain=[uid of sys-domain]
config.absRefPrefix = / (in order to get rid of PHP DOCUMENT_ROOT (or TYPO3_DOCUMENT_ROOT ?) otherwise wrongly present in all generated links.)
The result is now a well dynamically-generated newsletter, the date is OK, all links are correct and realUrl-compliant (no ../index.php?id=nnn) .... and you know what ?... We're happy ! :-)
Hope it will help !
Many thanks to everybody who answered (Markus, Urs...) or even thought of a possible solution...
P-H Silliau
so I have just finished a degree in computing and have just started industry related employment and wow... we really don't seem to learn much at uni, just the bare basics.
Anyway, I am learning Apex and attempting to write my first trigger. The online tutorials are pretty unforgiving and I find that they seem to all miss out what my brain is lacking.
I am writing a trigger to automatically send an email to a specified address, the sending the email part is fine however I want to send in the email what has been changed and read as to whether it anything has been changed. What I have so far is as follows:
trigger Test1 on Account (after update) {
if(Trigger.isUpdate) {
//Commit current transaction, reserver email capacity
Messaging.reserveSingleEmailCapacity(1);
//Create an email message object
Messaging.SingleEmailMessage mail = new Messaging.SingleEmailMessage();
List<Messaging.SendEmailResult> results = new list<Messaging.SendEmailResult>();
//hold email address
String[] toAddresses = new String[] {'example#example.com'};
//Assign new address string
mail.setToAddresses(toAddresses);
//specify return ad (assuming as being sent from server)
mail.setReplyTo('pwitherby#gmail.com');
//sender name
mail.setSenderDisplayName('Mr Apex Tester');
//Subject Specification
mail.setSubject('Subjected to Learning');
//And... the content
mail.setPlainTextBody('You have just changed sumek... this really what you want....?')
if (!results.get(0).isSuccess())
System.debug('That didnt really work did it? Reason: ' + results.get(0).getErrors()[0].getMessage());
}
}
So my main questions that I cant find an answer for:
Will this work at current? so will this send this email if anything in the schema gets altered/updated?
I want to put in the email body what has been altered and what it has been changed to i.e "you have changed " + whatsChanged + " to " + telephoneNumber.
How do I listen for changes or is it already doing that?
Am I writing this to a decent standard or is it just messy code!
Sorry to waffle, it is my biggest downfall however I struggle to augment my questions without it!
You don't need to activate a trigger just writing it is enough.
You can access the changed new values Through Trigger.new (and Trigger.old for old values)
For Trigger documentation refer here
Maybe a workflow is more suitable to what you are trying to do.
And finally don't worry too much from the start about standard of the code (or beauty), it makes difference only when your code gets big anyway.