-
Posts
493 -
Joined
-
Last visited
Content Type
Downloads
Release Notes
IPS4 Guides
IPS4 Developer Documentation
Invision Community Blog
Development Blog
Deprecation Tracker
Providers Directory
Forums
Events
Store
Gallery
Posts posted by IPCommerceFan
-
-
Yeah we currently use a template hack where we duplicate a bunch of elements (category sidebar, product groups on the index, possibly others) and specify which member groups can see what. Its messy, and would be amazing if product groups could have permissions of their own.
For our use case, we would use the group permissions to show resellers/vendors special packages only they can access, while simultaneously hiding the public-facing packages from them. The opposite would be true for guests and regular customers.
- OptimusBain and LiquidFractal
- 1
- 1
-
-
Ah, our use case doesn't involve any of that so it wasn't considered. 🤦♂️
-
I wrote this to sort downloads by filename. You should be able to use it to accomplish the reverse sort by changing the database query accordingly:
<div class='ipsPad'> <h1 class='ipsType_pageTitle'>{lang="download_your_files"}</h1> <p class='ipsType_reset ipsType_normal ipsType_light'>{lang="download_file_count" pluralize="\count( $files )"}</p> <hr class='ipsHr'> <ul class='ipsDataList ipsDataList_reducedSpacing'> {{$fileRecords = \IPS\Db::i()->select('*', 'downloads_files_records', array(array('record_file_id=?', $fileObject->id),'record_backup=0'),'record_realname ASC');}} {{foreach $fileRecords as $file}} {{$data = $file;}} {{$k = $data['record_id'];}} <li class='ipsDataItem'> <div class='ipsDataItem_main'> <h4 class='ipsDataItem_title ipsContained_container'><span class='ipsType_break ipsContained'>{{if $data['record_realname']}}{$data['record_realname']}{{else}}{{$pathBits = explode( '/', \IPS\Http\Url::external( $data['record_location'] )->data[ \IPS\Http\Url::COMPONENT_PATH ] );}}{expression="\count( $pathBits ) ? array_pop( $pathBits ) : $data['record_location']"}{{endif}}</span></h4> {{if $data['record_size']}}<p class='ipsType_reset ipsDataItem_meta'>{filesize="$data['record_size']"}</p>{{endif}} </div> {{if $waitingOn == $k}} <div class='ipsDataItem_generic ipsDataItem_size6 ipsType_warning'> <noscript>{lang="wait_x_seconds_noscript" pluralize="$waitingFor"}</noscript> </div> {{endif}} <div class='ipsDataItem_generic ipsDataItem_size4 ipsType_right'> <span class="ipsHide" data-role="downloadCounterContainer">{lang="download_begins_in"} <span data-role="downloadCounter"></span> {lang="seconds"}</span> <a href='{$fileObject->url()->setQueryString( array( 'do' => 'download', 'r' => $k, 'confirm' => 1, 't' => 1, 'version' => isset( \IPS\Request::i()->version ) ? \IPS\Request::i()->version : NULL ) )->csrf()}' class='ipsButton ipsButton_primary ipsButton_small' data-action="download" {{if member.group['idm_wait_period']}}data-wait='true'{{endif}}>{lang="download"}</a> </div> </li> {{endforeach}} </ul> </div>
-
Yes! I ran into this when building a plugin for the Dripcampaigns application. Reloading the page to clear the (cached?) modal information was the only way to fix it. It seems to be a universal problem with the way these toggles are handled. Thanks for putting together the reproduction case.
-
It would be interesting if the suite could count daily outgoing emails, and queue into batches anything in excess of a user-defined number. 200,300,5000, etc. An interface for managing/prioritizing emails would eventually be needed for cases where certain emails need to go out ahead of others in the queue.
-
Hi,
It looks like the Braintree -> PayPal integration may need some attention.
We recently changed our site from the "old" PayPal integration, to Braintree -> PayPal, and have had numerous customers report they can't purchase due to an error.
Looking at the invoice in the AdminCP, we see that the error states:
QuoteRefused
US state codes must be two characters to meet PayPal Seller Protection requirements.Since IPS stores customer states as full text - e.g Texas vs TX - I assume this must be the reason for this error message.
The funny thing is I tried purchasing something myself, and could not reproduce the error.
We've reverted back to the "old" PayPal method for now, but I think this is worth looking into.
Our site is running 4.6.10, FYI.
-
-
It looks like Samsung Pay is now (or perhaps was already) an option via Braintree. Since it seems great effort was put forth to flesh out the Braintree integration, I figure I should point out this new method is available, as I'm sure the intent was probably to support all available methods - also we'd like to use it. 🙂
Thanks!
-
-
Assuming you are accessing the database directly via MySQL, you could use the JSON_EXTRACT function (MySQL 5.7 and above).
SELECT address->>'$."addressLines"[0]' AS 'addressLine1', address->>'$."addressLines"[1]' AS 'addressLine2', address->>'$."city"' AS 'City', address->>'$."region"' AS 'Region', address->>'$."country"' AS 'Country', address->>'$."postalCode"' AS 'postalCode' FROM nexus_customer_addresses
The above example utilizes the shorthand for JSON_UNQUOTE(JSON_EXTRACT()):
https://dev.mysql.com/doc/refman/8.0/en/json-search-functions.html#operator_json-inline-path
-
4.6.7
All 3rd party apps/plugins disabled
Issue:"Too many redirects" blank page when attempting to manage a purchase with a 'YesNo' field type that has the 'Used to identify purchases?' option set. (you're not supposed to be able to set this option for a 'YesNo' type)
Repro:
- Create a nexus custom field with Field Type of Text, and specify 'Used to identify purchases?'
- Assign the field to a package, and generate a purchase with said package in it.
- Go to Manage Purchases, confirm the purchase can be managed.
- Change the field type to 'YesNo' (or some other type that doesn't use the 'Used to identify Purchases' toggle)
- Attempt to manage the purchase. This should result in a URL that apparently contains the csrf key appended to it, and a "ERR_TOO_MANY_REDIRECTS" browser error.
"No code" fix:
- Change the custom field back to 'Text'
- De-select 'Used to identify Purchases'
- Save
- Change the type back to 'YesNo'
- Save
I confirmed changing the setting for 'Used to identify Purchases' fixes this, but I figure if I ran into this organically, someone else might as well too and would come to support for help with it. Frankly I had no idea why I was suddenly unable to manage some purchases for a good while. lol
Here's what some poking around the $values revealed when saving the form:
Text -> Utip enabled:
- "cf_sticky":true
Text -> Utip disabled:
- "cf_sticky":false
YesNo -> Utip disabled:
- "cf_sticky":false
YesNo -> Utip enabled:
- "cf_sticky":1
It would seem the cf_sticky state is still being saved, but it is formatted incorrectly because the toggle isn't actually displayed on the form.
We don't actually want any YesNo field to be sticky though, since its not really useful info, so I'd suggest doing something like this in \IPS\nexus\Package\CustomField::formatFormValues()
if ($values['cf_sticky'] === 1){ $values['cf_sticky'] = FALSE; }
Tested via plugin, it fixes the problem.
[/Fringe case] lol
-
Just browsing through nexus\interface\gateways\paypal, it looks like you need to set the status when you save the transaction.
if ($status == 'paid') { // payment is complete if ( $transaction->status !== \IPS\nexus\Transaction::STATUS_PAID ) { $transaction->gw_id = $transactionId; $transaction->auth = NULL; $transaction->approve(); $transaction->status = \IPS\nexus\Transaction::STATUS_PAID; $transaction->save(); $transaction->sendNotification(); } }
It seems $transaction->approve() SHOULD do this for you, but if its not, I'd try doing it explicitly like its done in the paypal gateway. Maybe approve isn't doing it due to declaring "->approve(NULL)" as opposed to "->approve()"?
Incidentally (and feel free to ignore this section), I'm curious what some kind of debugging would capture at each step. One method I use is adding a function that looks something like this to the class I want to debug:
/** * Debugging Tool * * @param __LINE__ $magicLine Line in code * @param __FUNCTION__ $magicFunction Function in code * @param string $desc Unique descriptive text * @param mixed $markerData Data we want to capture * @return void */ static public function codeMarker( $magicLine, $magicFunction, $desc=NULL, $markerData=NULL ) { $hookID = ''; $filename = 'phpFilename'; \IPS\Db::i()->insert('dbg_table', array( 'debug_hook_id' => $hookID, 'debug_hook_filename' => $filename, //'debug_hook_plugin' => \IPS\Application::load(\IPS\Plugin\Hook::load( $hookID )->app)->directory, 'debug_hook_plugin' => 'pluginName', 'debug_line_number' => $magicLine, 'debug_function_name' => $magicFunction, 'debug_description' => $desc, 'debug_markerdata' => \is_array($markerData) ? substr(json_encode($markerData),0,2048) : $markerData, 'debug_timestamp' => str_pad(microtime(time()),15,"0",STR_PAD_RIGHT) )); }
Then add "code markers" to the code, run it, and see what turns up.
In this case I would hook into \IPS\nexus\Transaction::approve() and add:
static::codeMarker(__LINE__,__FUNCTION__,'_check_status_before_', $this->status); parent::approve(); static::codeMarker(__LINE__,__FUNCTION__,'_check_status_after_', $this->status);
Or even redeclare the function verbatim and insert markers as desired.
Then query the debug table to see what we caught. I'm not sure that this is an accepted or even a remotely efficient way of debugging, but its what works for me (better than error_log, debug_backtrace, etc since we are inserting markers directly into the code at the spot we want to inspect)
-
It appears STATUS_PAID is the closest thing to STATUS_APPROVED short of adding a new status yourself.
e.g.
const STATUS_PAID = 'okay'; // Transaction has been paid successfully const STATUS_PENDING = 'pend'; // Payment not yet submitted (for example, has been redirected to external site) const STATUS_WAITING = 'wait'; // Waiting for user (for example, a check is in the mail). Manual approval will be required const STATUS_HELD = 'hold'; // Transaction is being held for approval const STATUS_REVIEW = 'revw'; // Transaction, after being held for approval, has been flagged for review by staff const STATUS_REFUSED = 'fail'; // Transaction was refused const STATUS_REFUNDED = 'rfnd'; // Transaction has been refunded in full const STATUS_PART_REFUNDED = 'prfd'; // Transaction has been partially refunded const STATUS_GATEWAY_PENDING= 'gwpd'; // The gateway is processing the transaction const STATUS_DISPUTED = 'dspd'; // The customer disputed the transaction with their bank (filed a chargeback) const STATUS_APPROVED = 'appr'; // Added for additional status functionality
and then of course you'd have to decide how/when the status would be set.
As it stands though, the suite seems to treat PAID as being synonymous with APPROVED.
For instance, the sendNotification() funciton in \IPS\nexus\Transaction lists the notification key for STATUS_PAID as 'transactionApproved'.
-
Try using a unix timestamp, like so (this one is for Oct 1st 2021):
/api/core/search?sortby=newest&key=################################&type=forums_topic&start_after=1633064400
The results that are returned are given in DateTime:
{ "page": 1, "perPage": 25, "totalResults": 1, "totalPages": 1, "results": [ { "title": "Widget", "content": "", "class": "IPS\\nexus\\Package\\Item", "objectId": 9999, "itemClass": "IPS\\nexus\\Package\\Item", "itemId": 9999, "started": "2021-11-02T08:35:52Z", "updated": "2021-11-02T08:38:33Z", "itemUrl": "https:\/\/www.yourdomain.com\/store\/product\/9999-widget\/", "objectUrl": "https:\/\/www.yourdomain.com\/store\/product\/9999-widget\/?do=findComment&comment=1358", "reputation": 0, "comments": null, "reviews": 0, "container": "Widgets", "containerUrl": "https:\/\/www.yourdomain.com\/store\/category\/1-widgets\/", "author": "Guest", "authorUrl": null, "authorPhoto": "https:\/\/www.yourdomain.com\/applications\/core\/dev\/resources\/global\/default_photo.png", "authorPhotoThumbnail": "https:\/\/www.yourdomain.com\/applications\/core\/dev\/resources\/global\/default_photo.png", "tags": [] } ] }
But as far as the GET request goes, its in unixtime.
-
Have you tried adding the data-pageapp selector? It sounds redundant since you're talking about the default app, but perhaps it is needed.
-
When viewing a nexus invoice on the front end for a physical product, Pending shipping items show the nexus pfield ID instead of the name:If we change this in nexus -> front -> clients -> invoice (line 220):
<span class="ipsType_light"> {{foreach $item['details'] as $k => $v}} {lang="$k"}: {$v}<br> {{endforeach}} </span>
To this:
<span class="ipsType_light"> {{foreach $item['details'] as $k => $v}} {lang="nexus_pfield_$k"}: {$v}<br><br> {{endforeach}} </span>
We get this:
Thanks! -
Agreed, it felt very "fringe". Probably solar flares. lol
-
Unfortunately I don't know when this originated, as I hadn't tried to use the 2FA feature until today. I'm only theorizing it had to do with my install having been upgraded with long version gaps in-between and wanted to share my solution in case its of any benefit to others.
It is indeed resolved. The plugin I wrote was disabled and discarded, and I'm successfully using Google Authenticator. 👍
-
IC 4.6.7 / PHP 8 / MySQL 8
All 3rd party apps/plugins disabled
Not a fresh install - upgraded from 4.4.10 recently, 3.4.9 before that.
It seems, perhaps due to something missed in an upgrade routine, the Enabled/Disabled status for Two Factor Authentication handlers is missing. (it had never been used)
In IPS\core\modules\admin\settings\mfa.php, line 108
isEnabled() is run on the handler, which checks for the settings:
\IPS\Settings::i()->authy_enabled
\IPS\Settings::i()->questions_enabled
\IPS\Settings::i()->google_enabledThe settings have never been populated with a 0 or 1, and are instead null.
Since they are null, the "Enable/Disable" button doesn't know to appear here:
My solution to this was to write a plugin which modifies this, at line 108:
$handler->isEnabled()
To:
$handler->isEnabled() ?? 0
and the buttons appeared, with "Disabled" selected.
I proceeded to enable each item, then disable, and disabled the plugin. This wrote 0's to the setting for each handler:
Now I can freely enable/disable the MFA handlers without the plugin:
I'm not sure how this would be worked into a future update, whether by the method I used, or doing something in the upgrader to populate the null settings with 0's, but the issue existed for me so I figured I'd report it! 👍
-
Something like a "Service Fee"?
The only additional fees which work that way would be Tax rates, and those are always a percentage of each line item (product price and shipping rate have tax applied individually).In order to add a static amount to each order, you'd need a developer to write custom application or plugin for it which would add a new item to the invoice.
-
Hey @Maxxius, yeah, using a Pages block is just my way of quickly testing something out.
If we're talkin' page templates, then one thing to remember is anything encapsulated by double curly braces is parsed as PHP, and anything in single curly braces echoes the variable.
So, in a template, this would look like:
{{$apiOutput = \IPS\Member::loggedIn()->apiOutput();}} {$apiOutput['joined']} {$apiOutput['rank']['name']}
You could not, however, do:
{\IPS\Member::loggedIn()->apiOutput()['joined']}
since there is not a variable in the single curly braces.
Where in globalTemplate do you want this to appear, exactly?
-
This works in a custom Pages PHP block:
$output = ''; $apiOutput = \IPS\Member::loggedIn()->apiOutput(); $output .= json_encode($apiOutput); echo $output;
^ this will return all of the possible values.
If you wanted just rank title and registration date, you'd do:
$output .= $apiOutput['joined']; $output .= $apiOutput['rank']['name'];
To discover what your options are for working with the member object directly, you'd do:
$output .= json_encode(\IPS\Member::loggedIn()->_data);
At which point you'll discover the apiOutput method is a lot more straightforward, since you'd then need to learn all the functions necessary to call up the data that isn't in the member object itself.
e.g.:
$output .= \IPS\Member::loggedIn()->joined; $output .= \IPS\Member::loggedIn()->rank()->title;
Hope that helps!
-
Have you tried something like:
{{sort($images); sort($thumbs);}}
Before plugging them into the foreach loop?
sort() sorts by value, so if the value is the filename, it should align them.
[bug] 4.6.10 - Commerce List View w/ Required fields
in Technical Problems
Posted
4.6.10
all customizations disabled
default theme
I'm not sure how long this has existed, however I've encountered it while working on an application that adds custom validation to the package form.
Steps to reproduce:
=
If we add some instrumentation to listen in on \IPS\Helpers\Form::values() , we see that the "form_required" error is being added to the element, but is just not displaying correctly via the template:
Validation works great when accessing the package directly (via Grid view), or when updating the purchase form in the client area. It is only when the form is generated by the 'Choose Options' button that it behaves this way.
Frankly I don't use List view - I've considered just disabling it as an option - but I imagine some customers might prefer it, so please let me know if I can do or add anything to help get this resolved.