Jump to content

IPCommerceFan

Clients
  • 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

Everything posted by IPCommerceFan

  1. This might not be a bug per se, but something that could be clarified via some comments in the code for addHeader maybe? I'm working on an app which would allow an entire section to be toggled on or off. Part of this involves hiding a section header (via a YesNo for example) by its assigned ID. When I tried doing: $form = new \IPS\Helpers\Form; $form->add(new \IPS\Helpers\Form\YesNo('yesno_toggle', FALSE, FALSE, array('togglesOn' => array('my_header', 'text_field',)), NULL, NULL, NULL, 'yesno_toggle')); $form->addHeader('my_header',NULL,NULL,'my_header'); $form->add( new \IPS\Helpers\Form\Text( 'text_field', NULL, FALSE, array( 'placeholder' => 'Enter some text here' ), NULL, NULL, NULL, 'text_field' ) ); It did not work, however when I changed 'my_header' to 'form_header_my_header' in the 'togglesOn' list, it worked. $form = new \IPS\Helpers\Form; $form->add(new \IPS\Helpers\Form\YesNo('yesno_toggle', FALSE, FALSE, array('togglesOn' => array('form_header_my_header', 'text_field',)), NULL, NULL, NULL, 'yesno_toggle')); $form->addHeader('my_header',NULL,NULL,'my_header'); $form->add( new \IPS\Helpers\Form\Text( 'text_field', NULL, FALSE, array( 'placeholder' => 'Enter some text here' ), NULL, NULL, NULL, 'text_field' ) ); When toggling other form elements, just using the assigned ID works, so I feel like this should follow suit without the manually-added prefix. Its also of concern that it wasn't clear this was necessary. Maybe anything in a "togglesOn/togglesOff/toggles" array could be run through something that checks whether the id ties back to a form header or not, and applies the prefix automatically? I actually set out to report this as a bug with addHeader toggling simply not working, but in typing it up I realized what was actually going on and modified this post. Its funny how many things can be solved on your own by trying to tell someone about it. 😅
  2. 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: Create a custom text field, set it to Required, and assign it to a package = On the front end, view packages in List View. This adds a "Choose Options" button Click Choose Options, do not fill out any fields, and try to add to cart A new element will be added below the form each time "Add to cart" is clicked, instead of showing that the required field was not filled out If the field is filled out and add to cart is clicked, all the extra elements disappear and you can proceed to checkout: Without reloading the page - If you click Continue Shopping, and try to Add to Cart without entering anything in the field, you get this: 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.
  3. 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.
  4. You could try: $desc = \IPS\Member::loggedIn()->language()->get("nexus_package_{$item->id}_desc"); strip_tags($desc); substr($desc,0,1024); etc
  5. Ah, our use case doesn't involve any of that so it wasn't considered. 🤦‍♂️
  6. 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>
  7. 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.
  8. 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.
  9. 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: 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.
  10. 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!
  11. What about.. {{ $gtsym = '&gt;'; }} {{ ... $this . html_entity_decode($gtsym) . $that ... }} I didn't test it, so I'm not sure if that would simply lead right back where you started. It seems plausible though.
  12. 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
  13. 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
  14. 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)
  15. 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'.
  16. 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.
  17. Have you tried adding the data-pageapp selector? It sounds redundant since you're talking about the default app, but perhaps it is needed.
  18. 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!
  19. 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. 👍
  20. 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_enabled The 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! 👍
  21. 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.
  22. 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?
  23. 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!
×
×
  • Create New...