Function To Generate Download Keys For New Files

Hello!

I am facing a problem trying solve an issue related to order with products that received a new downloadable file.

When a product receive a new downloadable file, every order start to display the information about the new file however it is not available to download. I am trying to automate this process and make the file available without the necessity of the vendor goes to each order and active manually.

Just to explain better let me give a example:

User A buy Product B that have the Download C (after full payment activation), user A has automatic access to Download C.

In the next day the vendor add a new downloadable file called Download D. Now the old order from user A, display two downloads C and D, but the user A can only download file C. To be able to download the Document D, the vendor needs to go to the backend and activate manually.

Just image a vendor goes to hundred order and activate manually each of them? This doesnt make sense.

I already found a way to identify orders with downloadable files but couldnt find what function is responsable to generate the keys. I thought that could be the function fn_generate_ekeys_for_edp, but doesnt matter what information I try to pass, seems not to be working.

I think you should should add products.post.php controller for backend and add necessary actions for the update_file mode

Hi eComLabs!

I think you should should add products.post.php controller for backend and add necessary actions for the update_file mode

Yes! Is what I have in mind. Do you know what function is responsable to generate the ekeys for "files to sell"? The unique function that I found was fn_generate_ekeys_for_edp, but is not very clear to me what information should be passed as variables. I am not sure algo if this is the correct function because is said in the end that is for e-mail notification.

/**
 * Generates EDP ekeys for email notification
 *
 * @param array $statuses     order statuses
 * @param array $order_info   order information
 * @param array $active_files array with file download statuses
 *
 * @return array $edp_data
 */
function fn_generate_ekeys_for_edp(array $statuses, array $order_info, array $active_files = [])
{
    /**
     * Actions before generating ekeys for downloadable products (EDP)
     *
     * @param array $statuses       Order statuses
     * @param array $order_info     Order information
     * @param array $active_files   Array with file download statuses
     */
    fn_set_hook('generate_ekeys_for_edp_pre', $statuses, $order_info, $active_files);
$edp_data = array();
$order_statuses = fn_get_statuses(STATUSES_ORDER, [], true);

foreach ($order_info['products'] as $v) {

    // Generate ekey if EDP is ordered
    if (empty($v['extra']['is_edp']) || !YesNo::toBool($v['extra']['is_edp'])) {
        continue;
    }

    $activations = db_get_hash_single_array('SELECT activation_type, file_id FROM ?:product_files WHERE product_id = ?i AND status = ?s', ['file_id', 'activation_type'], $v['product_id'], ObjectStatuses::ACTIVE);

    foreach ($activations as $file_id => $activation_type) {
        // Check if ekey already was generated for this file
        $_ekey = db_get_row('SELECT ekey, active, file_id, product_id, order_id, ekey FROM ?:product_file_ekeys WHERE file_id = ?i AND order_id = ?i', $file_id, $order_info['order_id']);

        if (!empty($_ekey)) {
            $_ekey['activation'] = $activation_type;
            $paid_statuses = fn_get_settled_order_statuses();

            // If order status changed to "Processed"
            if (($activation_type === 'P') && !empty($statuses) && !isset($active_files[$v['product_id']][$file_id])) {
                if (in_array($statuses['status_to'], $paid_statuses)) {
                    $active_files[$v['product_id']][$file_id] = YesNo::YES;
                } else {
                    $active_files[$v['product_id']][$file_id] = YesNo::NO;
                }
            }

            if (!empty($active_files[$v['product_id']][$file_id])) {
                db_query('UPDATE ?:product_file_ekeys SET ?u WHERE file_id = ?i AND product_id = ?i AND order_id = ?i', ['active' => $active_files[$v['product_id']][$file_id]], $_ekey['file_id'], $_ekey['product_id'], $_ekey['order_id']);

                if ($active_files[$v['product_id']][$file_id] === YesNo::YES && $_ekey['active'] !== YesNo::YES) {
                    $edp_data[$v['product_id']]['files'][$file_id] = $_ekey;
                }
            }

        } else {
            $_data = [
                'file_id' => $file_id,
                'product_id' => $v['product_id'],
                'ekey' => md5(uniqid(rand())),
                'ttl' => (TIME + (Registry::get('settings.General.edp_key_ttl') * 60 * 60)),
                'order_id' => $order_info['order_id'],
                'activation' => $activation_type,
            ];

            // Activate the file if type is "Immediately" or "After full payment" and order statuses is from "paid" group
            if (
                $activation_type === 'I'
                || !empty($active_files[$v['product_id']][$file_id]) && $active_files[$v['product_id']][$file_id] === YesNo::YES
                || ($activation_type === 'P' && !empty($statuses)
                    && $order_statuses[$statuses['status_to']]['params']['inventory'] === 'D'
                    && substr_count('O', $statuses['status_to']) === 0 && (
                        $order_statuses[$statuses['status_from']]['params']['inventory'] !== 'D'
                        || substr_count('O', $statuses['status_from']) > 0
                    ))
            ) {
                $_data['active'] = YesNo::YES;
                $edp_data[$v['product_id']]['files'][$file_id] = $_data;
            }

            db_query('REPLACE INTO ?:product_file_ekeys ?e', $_data);
        }

        if (empty($edp_data[$v['product_id']]['files'][$file_id])) {
            continue;
        }

        $edp_data[$v['product_id']]['files'][$file_id]['file_size'] = db_get_field('SELECT file_size FROM ?:product_files WHERE file_id = ?i', $file_id);
        $edp_data[$v['product_id']]['files'][$file_id]['file_name'] = db_get_field('SELECT file_name FROM ?:product_file_descriptions WHERE file_id = ?i AND lang_code = ?s', $file_id, CART_LANGUAGE);
        $edp_data[$v['product_id']]['files'][$file_id]['url'] = fn_url('orders.get_file?file_id=' . $file_id . '&product_id=' . $v['product_id'] . '&ekey=' . $edp_data[$v['product_id']]['files'][$file_id]['ekey'], SiteArea::STOREFRONT, 'http');

        if (!isset($edp_data[$v['product_id']]['url'])) {
            $edp_data[$v['product_id']]['url'] = fn_url('orders.downloads?product_id=' . $v['product_id'] . '&ekey=' . $edp_data[$v['product_id']]['files'][$file_id]['ekey'], SiteArea::STOREFRONT, 'http');
        }

        if (isset($edp_data[$v['product_id']]['product'])) {
            continue;
        }

        $edp_data[$v['product_id']]['product'] = $v['product'];
    }
}

/**
 * Actions after generating ekeys for downloadable products (EDP)
 *
 * @param array $statuses       Order statuses
 * @param array $order_info     Order information
 * @param array $active_files   Array with file download statuses
 * @param array $edp_data       EDP ekeys for email notification
 */
fn_set_hook('generate_ekeys_for_edp_post', $statuses, $order_info, $active_files, $edp_data);

return $edp_data;

}

Here is example from the fn.cart.php file

$edp_data = fn_generate_ekeys_for_edp(array('status_from' => $status_from, 'status_to' => $status_to), $order_info);

What would be $order_info? The order id, all products from a order or only the downloadable?

Use before

$order_info = fn_get_order_info($order_id);

I created a script that generate the keys, I tried to use the default CS Cart function but couldnt make it work properly.

The unique thing that I couldnt solve was to make the script send a notification to users about the new files. Maybe someday I can make it work :)

use Tygh\Registry;
use Tygh\Enum\NotificationSeverity;
use Tygh\Enum\SiteArea;
use Tygh\Enum\YesNo;
use Tygh\Storage;
use Tygh\Enum\ProductZeroPriceActions;
use Faker\Factory as Faker;
use Illuminate\Support\Collection;
use Tygh\BlockManager\Block;
use Tygh\BlockManager\Location;
use Tygh\Embedded;
use Tygh\Enum\ObjectStatuses;
use Tygh\Enum\OrderDataTypes;
use Tygh\Enum\OutOfStockActions;
use Tygh\Enum\ProductTracking;
use Tygh\Enum\ProfileDataTypes;
use Tygh\Enum\ProfileFieldSections;
use Tygh\Enum\UserTypes;
use Tygh\Enum\ShippingRateTypes;
use Tygh\Languages\Languages;
use Tygh\Navigation\LastView;
use Tygh\Notifications\EventIdProviders\OrderProvider;
use Tygh\Pdf;
use Tygh\Shippings\Shippings;
use Tygh\Themes\Themes;
use Tygh\Tools\SecurityHelper;
use Tygh\Tygh;
use Tygh\Enum\VendorStatuses;

if (!defined(‘BOOTSTRAP’)) { die(‘Access denied’); }

function fn_autogeneratekey_update_product_post (&$product_data, &$product_id, $lang_code, $create) {

if (!empty($product_id)) {

    $updated_product_id = $product_id;

	/* Check Product Status Before Activate it */
    
    $status = db_get_field('SELECT status FROM ?:products WHERE product_id = ?i', $product_id);
    
    if ($status == 'A') {
    
        /* Find what Orders have The Product That Will be Updated */
        
        $paid_order_statuses = fn_get_settled_order_statuses();
        
        /* Find What Orders Need to Be Updated */
        
        $order_ids = db_get_fields("SELECT a.order_id FROM ?:order_details as a LEFT JOIN ?:orders as b ON a.order_id = b.order_id WHERE b.status IN (?a) AND a.product_id = ?i", $paid_order_statuses, $updated_product_id);
		
		/* Start the Process of Create Keys */
        
        foreach($order_ids as $order_id) {
			
			/* Check what files we need to create keys */
            
            $current_product_ekeys = db_get_fields("SELECT file_id FROM ?:product_file_ekeys WHERE product_id = ?i AND order_id = ?i", $updated_product_id, $order_id);
            $pending_product_ekeys = db_get_fields("SELECT file_id from ?:product_files WHERE file_id NOT IN (?a) AND product_id = ?i", $current_product_ekeys, $updated_product_id );
            
            foreach ($pending_product_ekeys as $pending_product_ekey) {
            
                $activation = db_get_fields("SELECT activation_type FROM ?:product_files WHERE file_id = ?i", $pending_product_ekey);
                
                $activation_type = ($activation === array('P') || $activation === array('I')) ? 'Y' : 'N';

                $ekey_data = [
                                'file_id' => $pending_product_ekey,
                                'product_id' => $updated_product_id,
                                'ekey' => md5(uniqid(rand())),
                                'ttl' => (TIME + (Registry::get('settings.General.edp_key_ttl') * 60 * 60)),
                                'order_id' => $order_id,
                                'active' => $activation_type,
                            ];
                
                
                db_query('INSERT INTO ?:product_file_ekeys ?e', $ekey_data);
             
            
            } 
            
        }
        
        
    }

}

}

I forgot to say, but this script need a product id to work ($product_id), so it can be used in several ways according the necessity.

If you still need help, our specialists can create additional notification about new files on the paid basis

I sent you a message.