Initial commit: Technical packages

This commit is contained in:
Ernad Husremovic 2025-08-29 15:20:51 +02:00
commit 3473fa71a0
873 changed files with 297766 additions and 0 deletions

View file

@ -0,0 +1,38 @@
/** @odoo-modules */
import { registry } from "@web/core/registry";
import { useService } from "@web/core/utils/hooks";
const { Component } = owl;
class IAPActionButtonsWidget extends Component {
setup() {
this.orm = useService("orm");
this.action = useService("action");
}
async onViewServicesClicked() {
const url = await this.orm.silent.call("iap.account", "get_account_url");
this.action.doAction({
type: "ir.actions.act_url",
url: url,
});
}
async onBuyLinkClicked() {
const url = await this.orm.silent.call("iap.account", "get_credits_url", [this.props.serviceName]);
this.action.doAction({
type: "ir.actions.act_url",
url: url,
});
}
}
IAPActionButtonsWidget.template = "iap.ActionButtonsWidget";
IAPActionButtonsWidget.extractProps = ({ attrs }) => {
return {
serviceName: attrs.service_name,
showServiceButtons: !Boolean(attrs.hide_service),
};
};
registry.category("view_widgets").add("iap_buy_more_credits", IAPActionButtonsWidget);

View file

@ -0,0 +1,13 @@
<?xml version="1.0" encoding="UTF-8"?>
<template id="template" xml:space="preserve">
<t t-name="iap.ActionButtonsWidget" owl="1">
<div class="mt-2 row">
<div class="col-sm">
<button t-on-click="onBuyLinkClicked" class="btn btn-link buy_credits px-0 o-hidden-ios"><i class="fa fa-arrow-right"/> Buy credits</button><br/>
<button t-if="props.showServiceButtons" t-on-click="onViewServicesClicked" class="btn btn-link px-0 o-hidden-ios"><i class="fa fa-arrow-right me-1"/> View My Services</button>
</div>
</div>
</t>
</template>

View file

@ -0,0 +1,88 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="680"
height="143"
version="1.1"
id="svg889"
sodipodi:docname="iap_logo.svg"
inkscape:version="0.92.3 (2405546, 2018-03-11)">
<metadata
id="metadata895">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<defs
id="defs893" />
<sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="1920"
inkscape:window-height="1015"
id="namedview891"
showgrid="false"
inkscape:zoom="1.9852941"
inkscape:cx="390.21297"
inkscape:cy="71.751852"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="1"
inkscape:current-layer="svg889" />
<g
fill="none"
fill-rule="evenodd"
id="g887">
<g
id="g881"
fill-rule="nonzero">
<path
d="M397.168 143.475c-30.083 0-54.47-24.387-54.47-54.47 0-30.084 24.387-54.472 54.47-54.472 30.084 0 54.471 24.388 54.471 54.471 0 30.084-24.387 54.471-54.47 54.471zm0-22.365c17.732 0 32.106-14.375 32.106-32.106S414.9 56.9 397.168 56.9c-17.73 0-32.105 14.374-32.105 32.105 0 17.731 14.374 32.106 32.105 32.106zm-115.435 22.365c-30.083 0-54.47-24.387-54.47-54.47 0-30.084 24.387-54.472 54.47-54.472 30.084 0 54.471 24.388 54.471 54.471 0 30.084-24.387 54.471-54.47 54.471zm0-22.365c17.732 0 32.106-14.375 32.106-32.106S299.465 56.9 281.733 56.9c-17.73 0-32.105 14.374-32.105 32.105 0 17.731 14.374 32.106 32.105 32.106z"
id="path875"
fill="#888" />
<path
d="M222.306 88.575l.001.43c0 30.083-24.387 54.47-54.47 54.47-30.084 0-54.471-24.387-54.471-54.47 0-30.084 24.387-54.472 54.47-54.472a54.23 54.23 0 0 1 32.84 11.009V10.825C200.676 4.847 205.52 0 211.498 0c5.977 0 10.822 4.851 10.822 10.825v77.191c0 .188-.005.374-.014.559zm-54.47 32.535c17.732 0 32.106-14.375 32.106-32.106S185.568 56.9 167.837 56.9c-17.732 0-32.106 14.374-32.106 32.105 0 17.731 14.374 32.106 32.106 32.106z"
id="path877"
fill="#888" />
<path
d="M54.97 143.354C24.887 143.354.5 118.967.5 88.884.5 58.8 24.887 34.411 54.97 34.411c30.084 0 54.471 24.388 54.471 54.471 0 30.084-24.387 54.471-54.47 54.471zm-.5-22.147c17.732 0 32.106-14.374 32.106-32.106 0-17.73-14.374-32.105-32.105-32.105-17.731 0-32.105 14.374-32.105 32.105 0 17.732 14.374 32.106 32.105 32.106z"
id="path879"
fill="#9C5789" />
</g>
<g
aria-label="IAP"
style="font-size:134px;font-family:Helvetica;letter-spacing:-4.4380002;fill:#8f8f8f"
id="text885">
<path
d="M 503.996,45.314 H 491.4 V 143 h 12.596 z"
style=""
id="path903" />
<path
d="m 572.41003,113.654 10.05,29.346 h 13.936 l -34.304,-97.686 h -16.08 l -34.84,97.686 h 13.266 l 10.318,-29.346 z m -3.484,-10.452 h -31.088 l 16.08,-44.488 z"
style=""
id="path905" />
<path
d="m 618.61984,101.594 h 30.686 c 7.638,0 13.668,-2.278 18.894,-6.968 5.896,-5.36 8.442,-11.658 8.442,-20.636 0,-18.358 -10.854,-28.676 -30.15,-28.676 h -40.334 V 143 h 12.462 z m 0,-10.988 V 56.302 h 25.996 c 11.926,0 19.028,6.432 19.028,17.152 0,10.72 -7.102,17.152 -19.028,17.152 z"
style=""
id="path907" />
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 3.9 KiB

View file

@ -0,0 +1,76 @@
odoo.define('iap.buy_more_credits', function (require) {
'use strict';
var widgetRegistry = require('web.widget_registry');
var Widget = require('web.Widget');
var core = require('web.core');
var rpc = require('web.rpc');
const utils = require('web.utils');
var QWeb = core.qweb;
var IAPBuyMoreCreditsWidget = Widget.extend({
className: 'o_field_iap_buy_more_credits',
/**
* @constructor
* Prepares the basic rendering of edit mode by setting the root to be a
* div.dropdown.open.
* @see FieldChar.init
*/
init: function (parent, data, options) {
this._super.apply(this, arguments);
this.service_name = options.attrs.service_name;
this.hideService = utils.toBoolElse(options.attrs.hide_service || '', false);
},
/**
* @override
*/
start: function () {
this.$widget = $(QWeb.render('iap.buy_more_credits', {'hideService': this.hideService}));
this.$buyLink = this.$widget.find('.buy_credits');
this.$widget.appendTo(this.$el);
this.$buyLink.click(this._getLink.bind(this));
if (!this.hideService) {
this.el.querySelector('.o_iap_view_my_services').addEventListener('click', this._getMyServices.bind(this));
}
},
//--------------------------------------------------------------------------
// Private
//--------------------------------------------------------------------------
_getLink: function () {
var self = this;
return rpc.query({
model: 'iap.account',
method: 'get_credits_url',
args: [this.service_name],
}, {
shadow: true,
}).then(function (url) {
return self.do_action({
type: 'ir.actions.act_url',
url: url,
});
});
},
/**
* @private
*/
_getMyServices() {
return this._rpc({
model: 'iap.account',
method: 'get_account_url',
}).then(url => {
this.do_action({type: 'ir.actions.act_url', url: url});
});
},
});
widgetRegistry.add('iap_buy_more_credits', IAPBuyMoreCreditsWidget);
return IAPBuyMoreCreditsWidget;
});

View file

@ -0,0 +1,56 @@
/** @odoo-module */
import { Dialog } from "@web/core/dialog/dialog";
import { registry } from "@web/core/registry";
import { useService } from "@web/core/utils/hooks";
const { Component, onWillStart } = owl;
class InsufficientCreditDialog extends Component {
setup() {
this.orm = useService("orm");
onWillStart(this.onWillStart);
}
async onWillStart() {
const { errorData } = this.props;
this.url = await this.orm.call("iap.account", "get_credits_url", [], {
base_url: errorData.base_url,
service_name: errorData.service_name,
credit: errorData.credit,
trial: errorData.trial,
});
this.style = errorData.body ? "padding:0;" : "";
const { _t } = this.env;
const { isEnterprise } = odoo.info;
if (errorData.trial && isEnterprise) {
this.buttonMessage = _t("Start a Trial at Odoo");
} else {
this.buttonMessage = _t("Buy credits");
}
}
buyCredits() {
window.open(this.url, "_blank");
this.props.close();
}
}
InsufficientCreditDialog.components = { Dialog };
InsufficientCreditDialog.template = "iap.InsufficientCreditDialog";
function insufficientCreditHandler(env, error, originalError) {
if (!originalError) {
return false;
}
const { data } = originalError;
if (data && data.name === "odoo.addons.iap.tools.iap_tools.InsufficientCreditError") {
env.services.dialog.add(InsufficientCreditDialog, {
errorData: JSON.parse(data.message),
});
return true;
}
return false;
}
registry
.category("error_handlers")
.add("insufficientCreditHandler", insufficientCreditHandler, { sequence: 0 });

View file

@ -0,0 +1,39 @@
<?xml version="1.0" encoding="UTF-8"?>
<template id="template" xml:space="preserve">
<!-- LAYOUT TEMPLATES -->
<t t-name="iap.InsufficientCreditDialog" owl="1">
<Dialog>
<div t-att-style="style">
<t t-if="props.errorData.body">
<div t-raw="props.errorData.body"/>
</t>
<t t-if="!props.errorData.body">
<t t-if="props.errorData.message">
<span t-esc="props.errorData.message"/>
</t>
<t t-if="!props.errorData.message">
<span>Insufficient credit to perform this service.</span>
</t>
</t>
<t t-set-slot="footer">
<button class="btn btn-primary" t-on-click="buyCredits" t-esc="buttonMessage"/>
<button class="btn" t-on-click="close">Cancel</button>
</t>
</div>
</Dialog>
</t>
<t t-extend="DashboardMain">
<t t-jquery=".o_web_settings_apps" t-operation="after">
<div class="o_web_settings_iap"></div>
</t>
</t>
<div t-name="iap.buy_more_credits" class="mt-2 row">
<div class="col-sm">
<button class="btn btn-link buy_credits px-0 o-hidden-ios"><i class="fa fa-arrow-right"/> Buy credits</button><br/>
<button t-if="!hideService" class="btn btn-link o_iap_view_my_services px-0 o-hidden-ios"><i class="fa fa-arrow-right me-1"/>View My Services</button>
</div>
</div>
</template>