Jump to content

Seb

Administrators
  • Posts

    674
  • Joined

  • Last visited

Posts posted by Seb

  1. On Wednesday 17th of August between 3am and 6am GMT we will be performing a substantial backend infrastructure change related to database scalability - needed to unlock multiple features down the road, but also before we start pushing and promoting Upmind. This is the last substantial backend feature we have been working on before we can begin to focus on feature requests, integrations and payment gateways.

    This change is substantial and involves database changes and migrations. As such there will be a period of service unavailability. We will show a notice relating to service maintenance. In all of our updates we attempt to never need to stop the system from working. However it is unavoidable in this instance.

    In our trials this maintenance lasted approximately 15 minutes. However we have scheduled a three hour maintenance window.

     

    • Like 3
  2. Ah ok - so something to clarify

    *Everything* that happens in Upmind is an API call. We're API first, so the entire admin area and client area is just you interfacing with our API

    If you lock down the IP restriction you therefore lock down both the admin area, and any API calls

    We will be changing the API setup and making API tokens, and those we will allow to be individually locked down to IPs also.

    • Like 1
  3. We've seen that someone has posted a job on Upwork for an Upmind integrator

    https://www.upwork.com/jobs/Connect-Upmind-billing-with-reseller-hosting-package_~01922ac9f583c77792

    This is great - while we've made our system as easy as possible we're very happy if there's some consultants and experts who help people get setup

    Is there interest in us creating a page of freelancer/consultants who could be contacted to help with setup? We wouldn't be making any recommendations or taking a cut or anything, but just facilitating the contact

    • Like 1
  4. That's essentially the way of showing a date stamp in a specific format, using PHP date

     

    https://www.php.net/manual/en/datetime.format.php

    So yes changing it to MM/DD/YYYY would then be 01/31/2023 rather than 31/01/2021 (DD/MM/YYYY)

    Day --- ---
    d Day of the month, 2 digits with leading zeros 01 to 31
    D A textual representation of a day, three letters Mon through Sun
    j Day of the month without leading zeros 1 to 31
    l (lowercase 'L') A full textual representation of the day of the week Sunday through Saturday
    N ISO 8601 numeric representation of the day of the week 1 (for Monday) through 7 (for Sunday)
    S English ordinal suffix for the day of the month, 2 characters st, nd, rd or th. Works well with j
    w Numeric representation of the day of the week 0 (for Sunday) through 6 (for Saturday)
    z The day of the year (starting from 0) 0 through 365
    Week --- ---
    W ISO 8601 week number of year, weeks starting on Monday Example: 42 (the 42nd week in the year)
    Month --- ---
    F A full textual representation of a month, such as January or March January through December
    m Numeric representation of a month, with leading zeros 01 through 12
    M A short textual representation of a month, three letters Jan through Dec
    n Numeric representation of a month, without leading zeros 1 through 12
    t Number of days in the given month 28 through 31
    Year --- ---
    L Whether it's a leap year 1 if it is a leap year, 0 otherwise.
    o ISO 8601 week-numbering year. This has the same value as Y, except that if the ISO week number (W) belongs to the previous or next year, that year is used instead. Examples: 1999 or 2003
    X An expanded full numeric representation of a year, at least 4 digits, with - for years BCE, and + for years CE. Examples: -0055, +0787, +1999, +10191
    x An expanded full numeric representation if requried, or a standard full numeral representation if possible (like Y). At least four digits. Years BCE are prefixed with a -. Years beyond (and including) 10000 are prefixed by a +. Examples: -0055, 0787, 1999, +10191
    Y A full numeric representation of a year, at least 4 digits, with - for years BCE. Examples: -0055, 0787, 1999, 2003, 10191
    y A two digit representation of a year Examples: 99 or 03
    Time --- ---
    a Lowercase Ante meridiem and Post meridiem am or pm
    A Uppercase Ante meridiem and Post meridiem AM or PM
    B Swatch Internet time 000 through 999
    g 12-hour format of an hour without leading zeros 1 through 12
    G 24-hour format of an hour without leading zeros 0 through 23
    h 12-hour format of an hour with leading zeros 01 through 12
    H 24-hour format of an hour with leading zeros 00 through 23
    i Minutes with leading zeros 00 to 59
    s Seconds with leading zeros 00 through 59
    u Microseconds. Note that date() will always generate 000000 since it takes an int parameter, whereas DateTime::format() does support microseconds if DateTime was created with microseconds. Example: 654321
    v Milliseconds. Same note applies as for u. Example: 654
    Timezone --- ---
    e Timezone identifier Examples: UTC, GMT, Atlantic/Azores
    I (capital i) Whether or not the date is in daylight saving time 1 if Daylight Saving Time, 0 otherwise.
    O Difference to Greenwich time (GMT) without colon between hours and minutes Example: +0200
    P Difference to Greenwich time (GMT) with colon between hours and minutes Example: +02:00
    p The same as P, but returns Z instead of +00:00 (available as of PHP 8.0.0) Example: +02:00
    T Timezone abbreviation, if known; otherwise the GMT offset. Examples: EST, MDT, +05
    Z Timezone offset in seconds. The offset for timezones west of UTC is always negative, and for those east of UTC is always positive. -43200 through 50400
    Full Date/Time --- ---
    c ISO 8601 date 2004-02-12T15:19:21+00:00
    r » RFC 2822/» RFC 5322 formatted date Example: Thu, 21 Dec 2000 16:01:07 +0200
    U Seconds since the Unix Epoch (January 1 1970 00:00:00 GMT) See also time()
    • Like 1
  5. We're definitely going to do this but just have a few more internal things we're sorting which wouldn't make sense to roadmap. We've spent most of the past month working on a huge restructure which enables scalability a lot more - as well as eventually specific locations for data residency etc. Unfortunately there's no 'feature' that it would map to - but we've not got many more things like that before we can start cranking out the features and integrations that are being asked for 🙂

    • Like 3
  6. We've got this on the roadmap.

    In the meantime I actually wrote a standalone script for this as a proof of concept using the Upmind API just to test how the AFS worked. It's very very basic and was simply a proof of concept, but should work fine for you until we do a proper integration into Upmind

    You'll need to configure the settings in Trustpilot

    --

    <?php
    
    class upmindAuth {
    
        public $api_url;
        public $origin;
        public $token;
        
        function __construct($origin){
            $this->api_url = 'api.upmind.io'; //live api url
            $this->origin = $origin; // Brand Origin
        }
        
        public function validate($username,$password){
            if (!$this->api_token(array('username'=>$username,'password'=>$password,'grant_type'=>'admin'))){
                return false;
            }
            return true;
        }
        
        public function api_token($params){
        
            $curl = curl_init();
            curl_setopt_array($curl, array(
              CURLOPT_URL => "https://".$this->api_url."/oauth/access_token",
              CURLOPT_RETURNTRANSFER => true,
              CURLOPT_ENCODING => "",
              CURLOPT_MAXREDIRS => 10,
              CURLOPT_TIMEOUT => 30,
              CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
              CURLOPT_CUSTOMREQUEST => "POST",
              CURLOPT_POSTFIELDS => json_encode($params),
              CURLOPT_HTTPHEADER => array(
                "accept: application/vnd.pub.v1+json",
                "cache-control: no-cache",
                "content-type: application/json",
                "origin: $this->origin",
              ),
            ));
        
            $response = curl_exec($curl);
            $err = curl_error($curl);
        
            if ($err) {
                return array('success'=>false,'error'=>"cURL Error #:" . $err);
            } else {
                $actor = json_decode($response);           
                $this->token = $actor->access_token;
                return true;
            }
        }
        
        public function get($endpoint){
          
            $curl = curl_init();
            curl_setopt_array($curl, array(
            CURLOPT_URL => "https://".$this->api_url.$endpoint,
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_ENCODING => "",
            CURLOPT_MAXREDIRS => 10,
            CURLOPT_TIMEOUT => 30,
            CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
            CURLOPT_CUSTOMREQUEST => "GET",
            CURLOPT_HTTPHEADER => array(
              "authorization: Bearer ".$this->token,
              "cache-control: no-cache",
              "origin: ".$this->origin,
            ),
          ));
        
          $response = curl_exec($curl);
        
          $err = curl_error($curl);
          
          if ($err) {
            echo "cURL Error #:" . $err;
          } else {
              return json_decode($response);
          }
        }
        
        public function post($endpoint,$params){
        
          $curl = curl_init();
          curl_setopt_array($curl, array(
          CURLOPT_URL => "https://".$this->api_url.$endpoint,
          CURLOPT_RETURNTRANSFER => true,
          CURLOPT_ENCODING => "",
          CURLOPT_MAXREDIRS => 10,
          CURLOPT_TIMEOUT => 30,
          CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
          CURLOPT_CUSTOMREQUEST => "POST",
          CURLOPT_POSTFIELDS => $params,
          CURLOPT_HTTPHEADER => array(
            "authorization: Bearer ".$this->token,
            "cache-control: no-cache",
            "origin: ".$this->origin,
          ),
        ));
        
        $response = curl_exec($curl);
        $err = curl_error($curl);
        
        if ($err) {
          echo "cURL Error #:" . $err;
        } else {
            return json_decode($response);
        }
        }
        
    }
    
    // Upmind API Creds
    $instance = ""; // Your Upmind Brand URL (E.g. https://my.domain.com)
    $user = ""; // username
    $pass = ""; // password
    
    //Trustpilot email
    $tpemail = ""; // Trustpilot invite email
    
    // Overrides
    $templateId = false;
    $senderEmail = ""; // e.g. [email protected]
    $senderName = ""; // e.g. Brand Name
    $replyTo = ""; // e.g. [email protected]
    
    $delay = 90; // Number of days after signup to send the email
    
    // Now we get latest orders from Upmind
    $upmind = new upmindAuth($instance);
    if (!$upmind->validate($user,$pass)){
        echo "Username and password incorrect"; die;
    }
    
    // Single API call to get the data we need
    $endpoint = "/api/admin/invoices?filter[category.slug]=new_contract&with=client,status,products,products.contracts_product,products.product.image&limit=50&offset=0&order=-created_at";
    if ($delay){
        $startdate = date("Y-m-d",time()-(86400*$delay));
        $endpoint = $endpoint."&filter[created_at%7Clte]=".$startdate;
    }
        
    $output = $upmind->get($endpoint);
    
    // Loop through data
    foreach ($output->data as $d){
        $skip = false;
        empty($client);
        $client['email'] = $d->client->email;//
        $client['name'] = $d->client->public_name;
        $client['orderid'] = $d->number;
        $client['products'] = array();
        
        foreach ($d->products as $p){
            $client['products'][] =
            array("name" => $p->product_name,
                "sku" => $p->product_id,
                "brand" => $p->invoice_brand->name,
                "productUrl" => $instance."/order/product?pid=".$p->product_id,
                "imageUrl" => $p->product->image->full_url
            );
            if ($p->contracts_product->status->code !== 'contract_active') {
                // This service is not active so do not request review
                $skip = true;
            }
        }
    
    
        $snippet = array(
            "recipientEmail" => $client['email'],
            "recipientName"=> $client['name'],
            "referenceId"=> "Order " . $client['orderid'],
            "locale" => "en-GB",
            "senderEmail" => $senderEmail,
            "senderName" => $senderName,
            "replyTo" => $replyTo,
            "products" => $client['products']
        );
    
    // Set overrride values if they exist
        if ($templateId){
            $snippet['templateId'] = $templateId;
        }
    
    if (!$skip){
        $emailContent = "<script type=\"application/json+trustpilot\">" . json_encode($snippet) . "</script>";
        mail($tpemail,"Invoice " . $client['orderid'],$emailContent);
    }
    
    }

     

     

    • Thanks 1
  7. We're likely to do this the other way around - Upmind will be easily embedded into a WordPress site using a plugin or shortcodes.

    This is one of our goals - we want to replace a lot of common plugin functionality that Upmind can replicate. Will start with contact forms (contact form 7 / ninjaforms) before moving to WooCommerce / EasyDigitalDownloads

    • Like 1
    • Thanks 2
  8. I think if we offer this it's likely to be some way away. Our codebase is an extremely high standard and billing is deeply integrated - it's not just a case of adding a charge. We'd also want to have refunds / tokenisations / reversals / pending payments etc.

    We're trying to get global coverage as quickly as possible, and focusing on gateways that it's easy to sign up with. 

×
×
  • Create New...