pacer.style.marginRight = makeEm(slant);
parts.unshift(spacer);
}
return buildCommon.makeSpan(["mop", "op-limits"], parts, options);
};
;// CONCATENATED MODULE: ./src/functions/op.js
// Limits, symbols
// Most operators have a large successor symbol, but these don't.
const noSuccessor = ["\\smallint"]; // NOTE: Unlike most `htmlBuilder`s, this one handles not only "op", but also
// "supsub" since some of them (like \int) can affect super/subscripting.
const op_htmlBuilder = (grp, options) => {
// Operators are handled in the TeXbook pg. 443-444, rule 13(a).
let supGroup;
let subGroup;
let hasLimits = false;
let group;
if (grp.type === "supsub") {
// If we have limits, supsub will pass us its group to handle. Pull
// out the superscript and subscript and set the group to the op in
// its base.
supGroup = grp.sup;
subGroup = grp.sub;
group = assertNodeType(grp.base, "op");
hasLimits = true;
} else {
group = assertNodeType(grp, "op");
}
const style = options.style;
let large = false;
if (style.size === src_Style.DISPLAY.size && group.symbol && !utils.contains(noSuccessor, group.name)) {
// Most symbol operators get larger in displaystyle (rule 13)
large = true;
}
let base;
if (group.symbol) {
// If this is a symbol, create the symbol.
const fontName = large ? "Size2-Regular" : "Size1-Regular";
let stash = "";
if (group.name === "\\oiint" || group.name === "\\oiiint") {
// No font glyphs yet, so use a glyph w/o the oval.
// TODO: When font glyphs are available, delete this code.
stash = group.name.slice(1);
group.name = stash === "oiint" ? "\\iint" : "\\iiint";
}
base = buildCommon.makeSymbol(group.name, fontName, "math", options, ["mop", "op-symbol", large ? "large-op" : "small-op"]);
if (stash.length > 0) {
// We're in \oiint or \oiiint. Overlay the oval.
// TODO: When font glyphs are available, delete this code.
const italic = base.italic;
const oval = buildCommon.staticSvg(stash + "Size" + (large ? "2" : "1"), options);
base = buildCommon.makeVList({
positionType: "individualShift",
children: [{
type: "elem",
elem: base,
shift: 0
}, {
type: "elem",
elem: oval,
shift: large ? 0.08 : 0
}]
}, options);
group.name = "\\" + stash;
base.classes.unshift("mop"); // $FlowFixMe
base.italic = italic;
}
} else if (group.body) {
// If this is a list, compose that list.
const inner = buildExpression(group.body, options, true);
if (inner.length === 1 && inner[0] instanceof SymbolNode) {
base = inner[0];
base.classes[0] = "mop"; // replace old mclass
} else {
base = buildCommon.makeSpan(["mop"], inner, options);
}
} else {
// Otherwise, this is a text operator. Build the text from the
// operator's name.
const output = [];
for (let i = 1; i < group.name.length; i++) {
output.push(buildCommon.mathsym(group.name[i], group.mode, options));
}
base = buildCommon.makeSpan(["mop"], output, options);
} // If content of op is a single symbol, shift it vertically.
let baseShift = 0;
let slant = 0;
if ((base instanceof SymbolNode || group.name === "\\oiint" || group.name === "\\oiiint") && !group.suppressBaseShift) {
// We suppress the shift of the base of \overset and \underset. Otherwise,
// shift the symbol so its center lies on the axis (rule 13). It
// appears that our fonts have the centers of the symbols already
// almost on the axis, so these numbers are very small. Note we
// don't actually apply this here, but instead it is used either in
// the vlist creation or separately when there are no limits.
baseShift = (base.height - base.depth) / 2 - options.fontMetrics().axisHeight; // The slant of the symbol is just its italic correction.
// $FlowFixMe
slant = base.italic;
}
if (hasLimits) {
return assembleSupSub(base, supGroup, subGroup, options, style, slant, baseShift);
} else {
if (baseShift) {
base.style.position = "relative";
base.style.top = makeEm(baseShift);
}
return base;
}
};
const op_mathmlBuilder = (group, options) => {
let node;
if (group.symbol) {
// This is a symbol. Just add the symbol.
node = new MathNode("mo", [makeText(group.name, group.mode)]);
if (utils.contains(noSuccessor, group.name)) {
node.setAttribute("largeop", "false");
}
} else if (group.body) {
// This is an operator with children. Add them.
node = new MathNode("mo", buildMathML_buildExpression(group.body, options));
} else {
// This is a text operator. Add all of the characters from the
// operator's name.
node = new MathNode("mi", [new TextNode(group.name.slice(1))]); // Append an ⁡.
// ref: https://www.w3.org/TR/REC-MathML/chap3_2.html#sec3.2.4
const operator = new MathNode("mo", [makeText("\u2061", "text")]);
if (group.parentIsSupSub) {
node = new MathNode("mrow", [node, operator]);
} else {
node = newDocumentFragment([node, operator]);
}
}
return node;
};
const singleCharBigOps = {
"\u220F": "\\prod",
"\u2210": "\\coprod",
"\u2211": "\\sum",
"\u22c0": "\\bigwedge",
"\u22c1": "\\bigvee",
"\u22c2": "\\bigcap",
"\u22c3": "\\bigcup",
"\u2a00": "\\bigodot",
"\u2a01": "\\bigoplus",
"\u2a02": "\\bigotimes",
"\u2a04": "\\biguplus",
"\u2a06": "\\bigsqcup"
};
defineFunction({
type: "op",
names: ["\\coprod", "\\bigvee", "\\bigwedge", "\\biguplus", "\\bigcap", "\\bigcup", "\\intop", "\\prod", "\\sum", "\\bigotimes", "\\bigoplus", "\\bigodot", "\\bigsqcup", "\\smallint", "\u220F", "\u2210", "\u2211", "\u22c0", "\u22c1", "\u22c2", "\u22c3", "\u2a00", "\u2a01", "\u2a02", "\u2a04", "\u2a06"],
props: {
numArgs: 0
},
handler: (_ref, args) => {
let {
parser,
funcName
} = _ref;
let fName = funcName;
if (fName.length === 1) {
fName = singleCharBigOps[fName];
}
return {
type: "op",
mode: parser.mode,
limits: true,
parentIsSupSub: false,
symbol: true,
name: fName
};
},
htmlBuilder: op_htmlBuilder,
mathmlBuilder: op_mathmlBuilder
}); // Note: calling defineFunction with a type that's already been defined only
// works because the same htmlBuilder and mathmlBuilder are being used.
defineFunction({
type: "op",
names: ["\\mathop"],
props: {
numArgs: 1,
primitive: true
},
handler: (_ref2, args) => {
let {
parser
} = _ref2;
const body = args[0];
return {
type: "op",
mode: parser.mode,
limits: false,
parentIsSupSub: false,
symbol: false,
body: ordargument(body)
};
},
htmlBuilder: op_htmlBuilder,
mathmlBuilder: op_mathmlBuilder
}); // There are 2 flags for operators; whether they produce limits in
// displaystyle, and whether they are symbols and should grow in
// displaystyle. These four groups cover the four possible choices.
const singleCharIntegrals = {
"\u222b": "\\int",
"\u222c": "\\iint",
"\u222d": "\\iiint",
"\u222e": "\\oint",
"\u222f": "\\oiint",
"\u2230": "\\oiiint"
}; // No limits, not symbols
defineFunction({
type: "op",
names: ["\\arcsin", "\\arccos", "\\arctan", "\\arctg", "\\arcctg", "\\arg", "\\ch", "\\cos", "\\cosec", "\\cosh", "\\cot", "\\cotg", "\\coth", "\\csc", "\\ctg", "\\cth", "\\deg", "\\dim", "\\exp", "\\hom", "\\ker", "\\lg", "\\ln", "\\log", "\\sec", "\\sin", "\\sinh", "\\sh", "\\tan", "\\tanh", "\\tg", "\\th"],
props: {
numArgs: 0
},
handler(_ref3) {
let {
parser,
funcName
} = _ref3;
return {
type: "op",
mode: parser.mode,
limits: false,
parentIsSupSub: false,
symbol: false,
name: funcName
};
},
htmlBuilder: op_htmlBuilder,
mathmlBuilder: op_mathmlBuilder
}); // Limits, not symbols
defineFunction({
type: "op",
names: ["\\det", "\\gcd", "\\inf", "\\lim", "\\max", "\\min", "\\Pr", "\\sup"],
props: {
numArgs: 0
},
handler(_ref4) {
let {
parser,
funcName
} = _ref4;
return {
type: "op",
mode: parser.mode,
limits: true,
parentIsSupSub: false,
symbol: false,
name: funcName
};
},
htmlBuilder: op_htmlBuilder,
mathmlBuilder: op_mathmlBuilder
}); // No limits, symbols
defineFunction({
type: "op",
names: ["\\int", "\\iint", "\\iiint", "\\oint", "\\oiint", "\\oiiint", "\u222b", "\u222c", "\u222d", "\u222e", "\u222f", "\u2230"],
props: {
numArgs: 0
},
handler(_ref5) {
let {
parser,
funcName
} = _ref5;
let fName = funcName;
if (fName.length === 1) {
fName = singleCharIntegrals[fName];
}
return {
type: "op",
mode: parser.mode,
limits: false,
parentIsSupSub: false,
symbol: true,
name: fName
};
},
htmlBuilder: op_htmlBuilder,
mathmlBuilder: op_mathmlBuilder
});
;// CONCATENATED MODULE: ./src/functions/operatorname.js
// NOTE: Unlike most `htmlBuilder`s, this one handles not only
// "operatorname", but also "supsub" since \operatorname* can
// affect super/subscripting.
const operatorname_htmlBuilder = (grp, options) => {
// Operators are handled in the TeXbook pg. 443-444, rule 13(a).
let supGroup;
let subGroup;
let hasLimits = false;
let group;
if (grp.type === "supsub") {
// If we have limits, supsub will pass us its group to handle. Pull
// out the superscript and subscript and set the group to the op in
// its base.
supGroup = grp.sup;
subGroup = grp.sub;
group = assertNodeType(grp.base, "operatorname");
hasLimits = true;
} else {
group = assertNodeType(grp, "operatorname");
}
let base;
if (group.body.length > 0) {
const body = group.body.map(child => {
// $FlowFixMe: Check if the node has a string `text` property.
const childText = child.text;
if (typeof childText === "string") {
return {
type: "textord",
mode: child.mode,
text: childText
};
} else {
return child;
}
}); // Consolidate function names into symbol characters.
const expression = buildExpression(body, options.withFont("mathrm"), true);
for (let i = 0; i < expression.length; i++) {
const child = expression[i];
if (child instanceof SymbolNode) {
// Per amsopn package,
// change minus to hyphen and \ast to asterisk
child.text = child.text.replace(/\u2212/, "-").replace(/\u2217/, "*");
}
}
base = buildCommon.makeSpan(["mop"], expression, options);
} else {
base = buildCommon.makeSpan(["mop"], [], options);
}
if (hasLimits) {
return assembleSupSub(base, supGroup, subGroup, options, options.style, 0, 0);
} else {
return base;
}
};
const operatorname_mathmlBuilder = (group, options) => {
// The steps taken here are similar to the html version.
let expression = buildMathML_buildExpression(group.body, options.withFont("mathrm")); // Is expression a string or has it something like a fraction?
let isAllString = true; // default
for (let i = 0; i < expression.length; i++) {
const node = expression[i];
if (node instanceof mathMLTree.SpaceNode) {// Do nothing
} else if (node instanceof mathMLTree.MathNode) {
switch (node.type) {
case "mi":
case "mn":
case "ms":
case "mspace":
case "mtext":
break;
// Do nothing yet.
case "mo":
{
const child = node.children[0];
if (node.children.length === 1 && child instanceof mathMLTree.TextNode) {
child.text = child.text.replace(/\u2212/, "-").replace(/\u2217/, "*");
} else {
isAllString = false;
}
break;
}
default:
isAllString = false;
}
} else {
isAllString = false;
}
}
if (isAllString) {
// Write a single TextNode instead of multiple nested tags.
const word = expression.map(node => node.toText()).join("");
expression = [new mathMLTree.TextNode(word)];
}
const identifier = new mathMLTree.MathNode("mi", expression);
identifier.setAttribute("mathvariant", "normal"); // \u2061 is the same as ⁡
// ref: https://www.w3schools.com/charsets/ref_html_entities_a.asp
const operator = new mathMLTree.MathNode("mo", [makeText("\u2061", "text")]);
if (group.parentIsSupSub) {
return new mathMLTree.MathNode("mrow", [identifier, operator]);
} else {
return mathMLTree.newDocumentFragment([identifier, operator]);
}
}; // \operatorname
// amsopn.dtx: \mathop{#1\kern\z@\operator@font#3}\newmcodes@
defineFunction({
type: "operatorname",
names: ["\\operatorname@", "\\operatornamewithlimits"],
props: {
numArgs: 1
},
handler: (_ref, args) => {
let {
parser,
funcName
} = _ref;
const body = args[0];
return {
type: "operatorname",
mode: parser.mode,
body: ordargument(body),
alwaysHandleSupSub: funcName === "\\operatornamewithlimits",
limits: false,
parentIsSupSub: false
};
},
htmlBuilder: operatorname_htmlBuilder,
mathmlBuilder: operatorname_mathmlBuilder
});
defineMacro("\\operatorname", "\\@ifstar\\operatornamewithlimits\\operatorname@");
;// CONCATENATED MODULE: ./src/functions/ordgroup.js
defineFunctionBuilders({
type: "ordgroup",
htmlBuilder(group, options) {
if (group.semisimple) {
return buildCommon.makeFragment(buildExpression(group.body, options, false));
}
return buildCommon.makeSpan(["mord"], buildExpression(group.body, options, true), options);
},
mathmlBuilder(group, options) {
return buildExpressionRow(group.body, options, true);
}
});
;// CONCATENATED MODULE: ./src/functions/overline.js
defineFunction({
type: "overline",
names: ["\\overline"],
props: {
numArgs: 1
},
handler(_ref, args) {
let {
parser
} = _ref;
const body = args[0];
return {
type: "overline",
mode: parser.mode,
body
};
},
htmlBuilder(group, options) {
// Overlines are handled in the TeXbook pg 443, Rule 9.
// Build the inner group in the cramped style.
const innerGroup = buildGroup(group.body, options.havingCrampedStyle()); // Create the line above the body
const line = buildCommon.makeLineSpan("overline-line", options); // Generate the vlist, with the appropriate kerns
const defaultRuleThickness = options.fontMetrics().defaultRuleThickness;
const vlist = buildCommon.makeVList({
positionType: "firstBaseline",
children: [{
type: "elem",
elem: innerGroup
}, {
type: "kern",
size: 3 * defaultRuleThickness
}, {
type: "elem",
elem: line
}, {
type: "kern",
size: defaultRuleThickness
}]
}, options);
return buildCommon.makeSpan(["mord", "overline"], [vlist], options);
},
mathmlBuilder(group, options) {
const operator = new mathMLTree.MathNode("mo", [new mathMLTree.TextNode("\u203e")]);
operator.setAttribute("stretchy", "true");
const node = new mathMLTree.MathNode("mover", [buildMathML_buildGroup(group.body, options), operator]);
node.setAttribute("accent", "true");
return node;
}
});
;// CONCATENATED MODULE: ./src/functions/phantom.js
defineFunction({
type: "phantom",
names: ["\\phantom"],
props: {
numArgs: 1,
allowedInText: true
},
handler: (_ref, args) => {
let {
parser
} = _ref;
const body = args[0];
return {
type: "phantom",
mode: parser.mode,
body: ordargument(body)
};
},
htmlBuilder: (group, options) => {
const elements = buildExpression(group.body, options.withPhantom(), false); // \phantom isn't supposed to affect the elements it contains.
// See "color" for more details.
return buildCommon.makeFragment(elements);
},
mathmlBuilder: (group, options) => {
const inner = buildMathML_buildExpression(group.body, options);
return new mathMLTree.MathNode("mphantom", inner);
}
});
defineFunction({
type: "hphantom",
names: ["\\hphantom"],
props: {
numArgs: 1,
allowedInText: true
},
handler: (_ref2, args) => {
let {
parser
} = _ref2;
const body = args[0];
return {
type: "hphantom",
mode: parser.mode,
body
};
},
htmlBuilder: (group, options) => {
let node = buildCommon.makeSpan([], [buildGroup(group.body, options.withPhantom())]);
node.height = 0;
node.depth = 0;
if (node.children) {
for (let i = 0; i < node.children.length; i++) {
node.children[i].height = 0;
node.children[i].depth = 0;
}
} // See smash for comment re: use of makeVList
node = buildCommon.makeVList({
positionType: "firstBaseline",
children: [{
type: "elem",
elem: node
}]
}, options); // For spacing, TeX treats \smash as a math group (same spacing as ord).
return buildCommon.makeSpan(["mord"], [node], options);
},
mathmlBuilder: (group, options) => {
const inner = buildMathML_buildExpression(ordargument(group.body), options);
const phantom = new mathMLTree.MathNode("mphantom", inner);
const node = new mathMLTree.MathNode("mpadded", [phantom]);
node.setAttribute("height", "0px");
node.setAttribute("depth", "0px");
return node;
}
});
defineFunction({
type: "vphantom",
names: ["\\vphantom"],
props: {
numArgs: 1,
allowedInText: true
},
handler: (_ref3, args) => {
let {
parser
} = _ref3;
const body = args[0];
return {
type: "vphantom",
mode: parser.mode,
body
};
},
htmlBuilder: (group, options) => {
const inner = buildCommon.makeSpan(["inner"], [buildGroup(group.body, options.withPhantom())]);
const fix = buildCommon.makeSpan(["fix"], []);
return buildCommon.makeSpan(["mord", "rlap"], [inner, fix], options);
},
mathmlBuilder: (group, options) => {
const inner = buildMathML_buildExpression(ordargument(group.body), options);
const phantom = new mathMLTree.MathNode("mphantom", inner);
const node = new mathMLTree.MathNode("mpadded", [phantom]);
node.setAttribute("width", "0px");
return node;
}
});
;// CONCATENATED MODULE: ./src/functions/raisebox.js
// Box manipulation
defineFunction({
type: "raisebox",
names: ["\\raisebox"],
props: {
numArgs: 2,
argTypes: ["size", "hbox"],
allowedInText: true
},
handler(_ref, args) {
let {
parser
} = _ref;
const amount = assertNodeType(args[0], "size").value;
const body = args[1];
return {
type: "raisebox",
mode: parser.mode,
dy: amount,
body
};
},
htmlBuilder(group, options) {
const body = buildGroup(group.body, options);
const dy = calculateSize(group.dy, options);
return buildCommon.makeVList({
positionType: "shift",
positionData: -dy,
children: [{
type: "elem",
elem: body
}]
}, options);
},
mathmlBuilder(group, options) {
const node = new mathMLTree.MathNode("mpadded", [buildMathML_buildGroup(group.body, options)]);
const dy = group.dy.number + group.dy.unit;
node.setAttribute("voffset", dy);
return node;
}
});
;// CONCATENATED MODULE: ./src/functions/relax.js
defineFunction({
type: "internal",
names: ["\\relax"],
props: {
numArgs: 0,
allowedInText: true,
allowedInArgument: true
},
handler(_ref) {
let {
parser
} = _ref;
return {
type: "internal",
mode: parser.mode
};
}
});
;// CONCATENATED MODULE: ./src/functions/rule.js
defineFunction({
type: "rule",
names: ["\\rule"],
props: {
numArgs: 2,
numOptionalArgs: 1,
allowedInText: true,
allowedInMath: true,
argTypes: ["size", "size", "size"]
},
handler(_ref, args, optArgs) {
let {
parser
} = _ref;
const shift = optArgs[0];
const width = assertNodeType(args[0], "size");
const height = assertNodeType(args[1], "size");
return {
type: "rule",
mode: parser.mode,
shift: shift && assertNodeType(shift, "size").value,
width: width.value,
height: height.value
};
},
htmlBuilder(group, options) {
// Make an empty span for the rule
const rule = buildCommon.makeSpan(["mord", "rule"], [], options); // Calculate the shift, width, and height of the rule, and account for units
const width = calculateSize(group.width, options);
const height = calculateSize(group.height, options);
const shift = group.shift ? calculateSize(group.shift, options) : 0; // Style the rule to the right size
rule.style.borderRightWidth = makeEm(width);
rule.style.borderTopWidth = makeEm(height);
rule.style.bottom = makeEm(shift); // Record the height and width
rule.width = width;
rule.height = height + shift;
rule.depth = -shift; // Font size is the number large enough that the browser will
// reserve at least `absHeight` space above the baseline.
// The 1.125 factor was empirically determined
rule.maxFontSize = height * 1.125 * options.sizeMultiplier;
return rule;
},
mathmlBuilder(group, options) {
const width = calculateSize(group.width, options);
const height = calculateSize(group.height, options);
const shift = group.shift ? calculateSize(group.shift, options) : 0;
const color = options.color && options.getColor() || "black";
const rule = new mathMLTree.MathNode("mspace");
rule.setAttribute("mathbackground", color);
rule.setAttribute("width", makeEm(width));
rule.setAttribute("height", makeEm(height));
const wrapper = new mathMLTree.MathNode("mpadded", [rule]);
if (shift >= 0) {
wrapper.setAttribute("height", makeEm(shift));
} else {
wrapper.setAttribute("height", makeEm(shift));
wrapper.setAttribute("depth", makeEm(-shift));
}
wrapper.setAttribute("voffset", makeEm(shift));
return wrapper;
}
});
;// CONCATENATED MODULE: ./src/functions/sizing.js
function sizingGroup(value, options, baseOptions) {
const inner = buildExpression(value, options, false);
const multiplier = options.sizeMultiplier / baseOptions.sizeMultiplier; // Add size-resetting classes to the inner list and set maxFontSize
// manually. Handle nested size changes.
for (let i = 0; i < inner.length; i++) {
const pos = inner[i].classes.indexOf("sizing");
if (pos < 0) {
Array.prototype.push.apply(inner[i].classes, options.sizingClasses(baseOptions));
} else if (inner[i].classes[pos + 1] === "reset-size" + options.size) {
// This is a nested size change: e.g., inner[i] is the "b" in
// `\Huge a \small b`. Override the old size (the `reset-` class)
// but not the new size.
inner[i].classes[pos + 1] = "reset-size" + baseOptions.size;
}
inner[i].height *= multiplier;
inner[i].depth *= multiplier;
}
return buildCommon.makeFragment(inner);
}
const sizeFuncs = ["\\tiny", "\\sixptsize", "\\scriptsize", "\\footnotesize", "\\small", "\\normalsize", "\\large", "\\Large", "\\LARGE", "\\huge", "\\Huge"];
const sizing_htmlBuilder = (group, options) => {
// Handle sizing operators like \Huge. Real TeX doesn't actually allow
// these functions inside of math expressions, so we do some special
// handling.
const newOptions = options.havingSize(group.size);
return sizingGroup(group.body, newOptions, options);
};
defineFunction({
type: "sizing",
names: sizeFuncs,
props: {
numArgs: 0,
allowedInText: true
},
handler: (_ref, args) => {
let {
breakOnTokenText,
funcName,
parser
} = _ref;
const body = parser.parseExpression(false, breakOnTokenText);
return {
type: "sizing",
mode: parser.mode,
// Figure out what size to use based on the list of functions above
size: sizeFuncs.indexOf(funcName) + 1,
body
};
},
htmlBuilder: sizing_htmlBuilder,
mathmlBuilder: (group, options) => {
const newOptions = options.havingSize(group.size);
const inner = buildMathML_buildExpression(group.body, newOptions);
const node = new mathMLTree.MathNode("mstyle", inner); // TODO(emily): This doesn't produce the correct size for nested size
// changes, because we don't keep state of what style we're currently
// in, so we can't reset the size to normal before changing it. Now
// that we're passing an options parameter we should be able to fix
// this.
node.setAttribute("mathsize", makeEm(newOptions.sizeMultiplier));
return node;
}
});
;// CONCATENATED MODULE: ./src/functions/smash.js
// smash, with optional [tb], as in AMS
defineFunction({
type: "smash",
names: ["\\smash"],
props: {
numArgs: 1,
numOptionalArgs: 1,
allowedInText: true
},
handler: (_ref, args, optArgs) => {
let {
parser
} = _ref;
let smashHeight = false;
let smashDepth = false;
const tbArg = optArgs[0] && assertNodeType(optArgs[0], "ordgroup");
if (tbArg) {
// Optional [tb] argument is engaged.
// ref: amsmath: \renewcommand{\smash}[1][tb]{%
// def\mb@t{\ht}\def\mb@b{\dp}\def\mb@tb{\ht\z@\z@\dp}%
let letter = "";
for (let i = 0; i < tbArg.body.length; ++i) {
const node = tbArg.body[i]; // $FlowFixMe: Not every node type has a `text` property.
letter = node.text;
if (letter === "t") {
smashHeight = true;
} else if (letter === "b") {
smashDepth = true;
} else {
smashHeight = false;
smashDepth = false;
break;
}
}
} else {
smashHeight = true;
smashDepth = true;
}
const body = args[0];
return {
type: "smash",
mode: parser.mode,
body,
smashHeight,
smashDepth
};
},
htmlBuilder: (group, options) => {
const node = buildCommon.makeSpan([], [buildGroup(group.body, options)]);
if (!group.smashHeight && !group.smashDepth) {
return node;
}
if (group.smashHeight) {
node.height = 0; // In order to influence makeVList, we have to reset the children.
if (node.children) {
for (let i = 0; i < node.children.length; i++) {
node.children[i].height = 0;
}
}
}
if (group.smashDepth) {
node.depth = 0;
if (node.children) {
for (let i = 0; i < node.children.length; i++) {
node.children[i].depth = 0;
}
}
} // At this point, we've reset the TeX-like height and depth values.
// But the span still has an HTML line height.
// makeVList applies "display: table-cell", which prevents the browser
// from acting on that line height. So we'll call makeVList now.
const smashedNode = buildCommon.makeVList({
positionType: "firstBaseline",
children: [{
type: "elem",
elem: node
}]
}, options); // For spacing, TeX treats \hphantom as a math group (same spacing as ord).
return buildCommon.makeSpan(["mord"], [smashedNode], options);
},
mathmlBuilder: (group, options) => {
const node = new mathMLTree.MathNode("mpadded", [buildMathML_buildGroup(group.body, options)]);
if (group.smashHeight) {
node.setAttribute("height", "0px");
}
if (group.smashDepth) {
node.setAttribute("depth", "0px");
}
return node;
}
});
;// CONCATENATED MODULE: ./src/functions/sqrt.js
defineFunction({
type: "sqrt",
names: ["\\sqrt"],
props: {
numArgs: 1,
numOptionalArgs: 1
},
handler(_ref, args, optArgs) {
let {
parser
} = _ref;
const index = optArgs[0];
const body = args[0];
return {
type: "sqrt",
mode: parser.mode,
body,
index
};
},
htmlBuilder(group, options) {
// Square roots are handled in the TeXbook pg. 443, Rule 11.
// First, we do the same steps as in overline to build the inner group
// and line
let inner = buildGroup(group.body, options.havingCrampedStyle());
if (inner.height === 0) {
// Render a small surd.
inner.height = options.fontMetrics().xHeight;
} // Some groups can return document fragments. Handle those by wrapping
// them in a span.
inner = buildCommon.wrapFragment(inner, options); // Calculate the minimum size for the \surd delimiter
const metrics = options.fontMetrics();
const theta = metrics.defaultRuleThickness;
let phi = theta;
if (options.style.id < src_Style.TEXT.id) {
phi = options.fontMetrics().xHeight;
} // Calculate the clearance between the body and line
let lineClearance = theta + phi / 4;
const minDelimiterHeight = inner.height + inner.depth + lineClearance + theta; // Create a sqrt SVG of the required minimum size
const {
span: img,
ruleWidth,
advanceWidth
} = delimiter.sqrtImage(minDelimiterHeight, options);
const delimDepth = img.height - ruleWidth; // Adjust the clearance based on the delimiter size
if (delimDepth > inner.height + inner.depth + lineClearance) {
lineClearance = (lineClearance + delimDepth - inner.height - inner.depth) / 2;
} // Shift the sqrt image
const imgShift = img.height - inner.height - lineClearance - ruleWidth;
inner.style.paddingLeft = makeEm(advanceWidth); // Overlay the image and the argument.
const body = buildCommon.makeVList({
positionType: "firstBaseline",
children: [{
type: "elem",
elem: inner,
wrapperClasses: ["svg-align"]
}, {
type: "kern",
size: -(inner.height + imgShift)
}, {
type: "elem",
elem: img
}, {
type: "kern",
size: ruleWidth
}]
}, options);
if (!group.index) {
return buildCommon.makeSpan(["mord", "sqrt"], [body], options);
} else {
// Handle the optional root index
// The index is always in scriptscript style
const newOptions = options.havingStyle(src_Style.SCRIPTSCRIPT);
const rootm = buildGroup(group.index, newOptions, options); // The amount the index is shifted by. This is taken from the TeX
// source, in the definition of `\r@@t`.
const toShift = 0.6 * (body.height - body.depth); // Build a VList with the superscript shifted up correctly
const rootVList = buildCommon.makeVList({
positionType: "shift",
positionData: -toShift,
children: [{
type: "elem",
elem: rootm
}]
}, options); // Add a class surrounding it so we can add on the appropriate
// kerning
const rootVListWrap = buildCommon.makeSpan(["root"], [rootVList]);
return buildCommon.makeSpan(["mord", "sqrt"], [rootVListWrap, body], options);
}
},
mathmlBuilder(group, options) {
const {
body,
index
} = group;
return index ? new mathMLTree.MathNode("mroot", [buildMathML_buildGroup(body, options), buildMathML_buildGroup(index, options)]) : new mathMLTree.MathNode("msqrt", [buildMathML_buildGroup(body, options)]);
}
});
;// CONCATENATED MODULE: ./src/functions/styling.js
const styling_styleMap = {
"display": src_Style.DISPLAY,
"text": src_Style.TEXT,
"script": src_Style.SCRIPT,
"scriptscript": src_Style.SCRIPTSCRIPT
};
defineFunction({
type: "styling",
names: ["\\displaystyle", "\\textstyle", "\\scriptstyle", "\\scriptscriptstyle"],
props: {
numArgs: 0,
allowedInText: true,
primitive: true
},
handler(_ref, args) {
let {
breakOnTokenText,
funcName,
parser
} = _ref;
// parse out the implicit body
const body = parser.parseExpression(true, breakOnTokenText); // TODO: Refactor to avoid duplicating styleMap in multiple places (e.g.
// here and in buildHTML and de-dupe the enumeration of all the styles).
// $FlowFixMe: The names above exactly match the styles.
const style = funcName.slice(1, funcName.length - 5);
return {
type: "styling",
mode: parser.mode,
// Figure out what style to use by pulling out the style from
// the function name
style,
body
};
},
htmlBuilder(group, options) {
// Style changes are handled in the TeXbook on pg. 442, Rule 3.
const newStyle = styling_styleMap[group.style];
const newOptions = options.havingStyle(newStyle).withFont('');
return sizingGroup(group.body, newOptions, options);
},
mathmlBuilder(group, options) {
// Figure out what style we're changing to.
const newStyle = styling_styleMap[group.style];
const newOptions = options.havingStyle(newStyle);
const inner = buildMathML_buildExpression(group.body, newOptions);
const node = new mathMLTree.MathNode("mstyle", inner);
const styleAttributes = {
"display": ["0", "true"],
"text": ["0", "false"],
"script": ["1", "false"],
"scriptscript": ["2", "false"]
};
const attr = styleAttributes[group.style];
node.setAttribute("scriptlevel", attr[0]);
node.setAttribute("displaystyle", attr[1]);
return node;
}
});
;// CONCATENATED MODULE: ./src/functions/supsub.js
/**
* Sometimes, groups perform special rules when they have superscripts or
* subscripts attached to them. This function lets the `supsub` group know that
* Sometimes, groups perform special rules when they have superscripts or
* its inner element should handle the superscripts and subscripts instead of
* handling them itself.
*/
const htmlBuilderDelegate = function (group, options) {
const base = group.base;
if (!base) {
return null;
} else if (base.type === "op") {
// Operators handle supsubs differently when they have limits
// (e.g. `\displaystyle\sum_2^3`)
const delegate = base.limits && (options.style.size === src_Style.DISPLAY.size || base.alwaysHandleSupSub);
return delegate ? op_htmlBuilder : null;
} else if (base.type === "operatorname") {
const delegate = base.alwaysHandleSupSub && (options.style.size === src_Style.DISPLAY.size || base.limits);
return delegate ? operatorname_htmlBuilder : null;
} else if (base.type === "accent") {
return utils.isCharacterBox(base.base) ? htmlBuilder : null;
} else if (base.type === "horizBrace") {
const isSup = !group.sub;
return isSup === base.isOver ? horizBrace_htmlBuilder : null;
} else {
return null;
}
}; // Super scripts and subscripts, whose precise placement can depend on other
// functions that precede them.
defineFunctionBuilders({
type: "supsub",
htmlBuilder(group, options) {
// Superscript and subscripts are handled in the TeXbook on page
// 445-446, rules 18(a-f).
// Here is where we defer to the inner group if it should handle
// superscripts and subscripts itself.
const builderDelegate = htmlBuilderDelegate(group, options);
if (builderDelegate) {
return builderDelegate(group, options);
}
const {
base: valueBase,
sup: valueSup,
sub: valueSub
} = group;
const base = buildGroup(valueBase, options);
let supm;
let subm;
const metrics = options.fontMetrics(); // Rule 18a
let supShift = 0;
let subShift = 0;
const isCharacterBox = valueBase && utils.isCharacterBox(valueBase);
if (valueSup) {
const newOptions = options.havingStyle(options.style.sup());
supm = buildGroup(valueSup, newOptions, options);
if (!isCharacterBox) {
supShift = base.height - newOptions.fontMetrics().supDrop * newOptions.sizeMultiplier / options.sizeMultiplier;
}
}
if (valueSub) {
const newOptions = options.havingStyle(options.style.sub());
subm = buildGroup(valueSub, newOptions, options);
if (!isCharacterBox) {
subShift = base.depth + newOptions.fontMetrics().subDrop * newOptions.sizeMultiplier / options.sizeMultiplier;
}
} // Rule 18c
let minSupShift;
if (options.style === src_Style.DISPLAY) {
minSupShift = metrics.sup1;
} else if (options.style.cramped) {
minSupShift = metrics.sup3;
} else {
minSupShift = metrics.sup2;
} // scriptspace is a font-size-independent size, so scale it
// appropriately for use as the marginRight.
const multiplier = options.sizeMultiplier;
const marginRight = makeEm(0.5 / metrics.ptPerEm / multi "301", "message" => "ERROR - [wsPolizasAnalytics] Parametros incompletos para el Servicio Web, faltan el appOwner");
$Resultado = json_encode($j_array);
echo $Resultado;
return $Resultado;
}
if($anio == "")
{
$j_array = array('code' => "302", "message" => "ERROR - [wsPolizasAnalytics] Parametros incompletos para el Servicio Web, faltan el Anio de vigencia");
$Resultado = json_encode($j_array);
echo $Resultado;
return $Resultado;
}
if($mes == "")
{
$j_array = array('code' => "303", "message" => "ERROR - [wsPolizasAnalytics] Parametros incompletos para el Servicio Web, faltan el Mes de vigencia");
$Resultado = json_encode($j_array);
echo $Resultado;
return $Resultado;
}
if($organi_id_Analytics == "")
{
$j_array = array('code' => "304", "message" => "ERROR - [wsPolizasAnalytics] Parametros incompletos para el Servicio Web, faltan el Organization ID de Analytics");
$Resultado = json_encode($j_array);
echo $Resultado;
return $Resultado;
}
if($RFC == "")
{
$j_array = array('code' => "305", "message" => "ERROR - [wsPolizasAnalytics] Parametros incompletos para el Servicio Web, faltan el RFC");
$Resultado = json_encode($j_array);
echo $Resultado;
return $Resultado;
}
if($idWorkspace == "")
{
$j_array = array('code' => "306", "message" => "ERROR - [wsPolizasAnalytics] Parametros incompletos para el Servicio Web, faltan el ID del workspace");
$Resultado = json_encode($j_array);
echo $Resultado;
return $Resultado;
}
if($idView == "")
{
$j_array = array('code' => "307", "message" => "ERROR - [wsPolizasAnalytics] Parametros incompletos para el Servicio Web, faltan el Organization ID de la vista");
$Resultado = json_encode($j_array);
echo $Resultado;
return $Resultado;
}
$dirBase = realpath("../");
### DEFINICIÓN DE CONSTANTES ###################################################
$SendaPEM = "archs_pem/";
$SendaXML = "archs_xml/";
$SendaZIP = "archs_zip/";
#----------------------------------------------------------------
#== Llamado para generar el token para donatello
#----------------------------------------------------------------
$curl = curl_init();
curl_setopt_array($curl, array(
CURLOPT_URL => 'https://donatello.aptuslegal.app/oauth/token/'.$organi_id_Analytics,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => '',
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 0,
CURLOPT_FOLLOWLOCATION => true,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => 'GET',
CURLOPT_HTTPHEADER => array(
'Authorization: Token e68d5a079f937ea29ad2ec5a5b105b75491a0e0c'
),
));
$response = curl_exec($curl);
curl_close($curl);
// Decodificamos la respuesta JSON
$data = json_decode($response, true);
// Accedemos al valor de 'access_token de donatello'
$access_token = $data['access_token'];
#----------------------------------------------------------------
#== Hacemos el llamado para generar la obtención de los datos en la operación Bulk y obtenemos el Job ID.
#----------------------------------------------------------------
$curl = curl_init();
// $dia = obtenerDiasDelMes($mes);
$anio = "2025";
$mes = "04";
$dia = "09";
if($dia == "Formato de mes inválido."){
$j_array = array('code' => "309", "message" => "ERROR - [wsPolizasAnalytics] El formato del parámetro del mes no es valido");
$Resultado = json_encode($j_array);
echo $Resultado;
return $Resultado;
}
curl_setopt_array($curl, array(
CURLOPT_URL => 'https://analyticsapi.zoho.com/restapi/v2/bulk/workspaces/'.$idWorkspace.'/views/'.$idView.'/data?CONFIG=%7B%22criteria%22%3A%22%5C%22Fecha%20de%20transaccion%5C%22%20between%20%27'.$anio.'-'.$mes.'-09%27%20and%20%27'.$anio.'-'.$mes.'-'.$dia.'%27%22%2C%20%22responseFormat%22%3A%22json%22%7D',
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => '',
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 0,
CURLOPT_FOLLOWLOCATION => true,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => 'GET',
CURLOPT_HTTPHEADER => array(
'ZANALYTICS-ORGID: '.$organi_id_Analytics,
'Authorization: Zoho-oauthtoken '.$access_token,
'Content-Type: application/json'
),
));
$response = curl_exec($curl);
curl_close($curl);
$responseData = json_decode($response, true);
ob_start();
echo '
';
print_r($responseData);
echo '
';
$debug_output = ob_get_clean();
// Acceder al 'jobId'
$jobId = $responseData['data']['jobId'];
#----------------------------------------------------------------
#== Obtenemos el status del JobId para saber si se puede descargar la respuesta
#----------------------------------------------------------------
$jobStatus = "JOB IN PROGRESS";
while ($jobStatus === "JOB IN PROGRESS") {
$curl = curl_init();
curl_setopt_array($curl, array(
CURLOPT_URL => 'https://analyticsapi.zoho.com/restapi/v2/bulk/workspaces/'.$idWorkspace.'/exportjobs/'.$jobId,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => '',
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 0,
CURLOPT_FOLLOWLOCATION => true,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => 'GET',
CURLOPT_HTTPHEADER => array(
'ZANALYTICS-ORGID: '.$organi_id_Analytics,
'Authorization: Zoho-oauthtoken '.$access_token
),
));
$response = curl_exec($curl);
// Decodificar la respuesta JSON
$responseData = json_decode($response, true);
// Verificar el status del trabajo
if (isset($responseData['data']['jobStatus'])) {
$jobStatus = $responseData['data']['jobStatus'];
} else {
// Si no se encuentra jobStatus en la respuesta, salir del ciclo
$j_array = array('code' => "311", "message" => "ERROR - [wsPolizasAnalytics] Error al esperar el Status de JobId de Analytics");
$Resultado = json_encode($j_array);
echo $Resultado;
return $Resultado;
}
// Esperar 5 segundos antes de volver a consultar
sleep(5);
}
//Si se obtiene un status diferente al esperado lo interpreta como error
if($jobStatus != "JOB COMPLETED"){
$j_array = array('code' => "312", "message" => "ERROR - [wsPolizasAnalytics] Error el Status del JobId inesperado");
$Resultado = json_encode($j_array);
echo $Resultado;
return $Resultado;
}
if (isset($responseData['data']['downloadUrl'])) {
$downloadUrl = $responseData['data']['downloadUrl'];
// echo "Download URL: " . $downloadUrl;
} else {
$j_array = array('code' => "313", "message" => "ERROR - [wsPolizasAnalytics] Error al obtener el downloadUrl de Analytics");
$Resultado = json_encode($j_array);
echo $Resultado;
return $Resultado;
}
#----------------------------------------------------------------
#== Llamado para la obtención de los datos en formato JSON de la vista de Analytics.
#----------------------------------------------------------------
$curl = curl_init();
curl_setopt_array($curl, array(
CURLOPT_URL => $downloadUrl,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => '',
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 0,
CURLOPT_FOLLOWLOCATION => true,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => 'GET',
CURLOPT_HTTPHEADER => array(
'ZANALYTICS-ORGID: '.$organi_id_Analytics,
'Authorization: Zoho-oauthtoken '.$access_token
),
));
$response = curl_exec($curl);
curl_close($curl);
// Decodificar el JSON
$responseData = json_decode($response, true);
// Verificar si el campo 'data' existe
if (isset($responseData['data'])) {
#----------------------------------------------------------------
#== Creación de la variable de tipo DOM, aquí se conforma el XML a timbrar posteriormente.
#----------------------------------------------------------------
$xml = new DOMdocument('1.0', 'UTF-8');
$root = $xml->createElement("Polizas");
$root = $xml->appendChild($root);
#== Se crea e inserta el primer nodo donde se declaran los namespaces ======
cargaAttNodo(
$root, array("xsi:schemaLocation"=>"www.sat.gob.mx/esquemas/ContabilidadE/1_1/PolizasPeriodo http://www.sat.gob.mx/esquemas/ContabilidadE/1_1/CatalogosParaEsqContE/CatalogosParaEsqContE.xsd",
"xmlns:Polizas"=>"www.sat.gob.mx/esquemas/ContabilidadE/1_1/AuxiliarFolios",
"xmlns:xsi"=>"http://www.w3.org/2001/XMLSchema")
);
#== Rutina de integración de nodos =========================================
cargaAttNodo($root, array(
"Version"=>"1.3",
"RFC"=>$RFC,
"Mes"=>$mes,
"Anio"=>$anio
)
);
$sumTotalDebe = 0;
$sumTotalHaber = 0;
$totalDebe = 0;
$totalHaber = 0;
$polizaControl = "";
$polizaNodo = null; // Variable para mantener la referencia al nodo Poliza
$numeroTotalPolizas = 0;
$array = array_reverse($responseData['data']);
foreach ($array as $item) {
// Asignar cada valor a variables
$tipoPoliza = $item['Tipo Poliza'];
$transaccion = $item['Transaccion'];
$fechaTransaccion = str_replace('.', '-', $item['Fecha de transaccion']);
$idCuenta = $item['ID de la cuenta'];
$nombre = $item['Nombre'];
$debe = $item['Debe'];
$haber = $item['Haber'];
$creditoDebitoTotal = $item['Credito-Debito - Total'];
$debitoCreditoTotal = $item['Debito-Credito Total'];
$concepto = $item['Concepto'];
$numCta = $item['NumCta'];
// Cuando detectas una nueva transacción (nueva póliza)
if($transaccion != $polizaControl){
// Si ya hay una póliza en proceso, agregas el atributo MontoTotal a la póliza anterior
if ($polizaNodo !== null) {
$montoTotal = $totalDebe - $totalHaber;
$polizaNodo->setAttribute("MontoTotal", number_format($montoTotal, 2, '.', '')); // Agregar MontoTotal
}
// Crear una nueva póliza
$polizaControl = $transaccion;
$Poliza = $xml->createElement("Poliza");
$polizaNodo = $root->appendChild($Poliza);
cargaAttNodo($polizaNodo, array(
"NumUnIdenPol" => $transaccion,
"Fecha" => $fechaTransaccion,
"Concepto" => $tipoPoliza
));
// Reiniciar los totales para la nueva póliza
$totalDebe = 0;
$totalHaber = 0;
}
// Crear un nodo Transaccion y agregarlo a la póliza actual
$transaccion = $xml->createElement("Transaccion");
$nodo = $Poliza->appendChild($transaccion);
cargaAttNodo($nodo, array(
"NumCta" => $numCta,
"DesCta" => $nombre,
"Concepto" => $concepto,
"Debe" => $debe,
"Haber" => $haber
));
// Acumular los valores de Debe y Haber
$totalDebe += (float)$debe;
$totalHaber += (float)$haber;
// Acumular los totales generales
$sumTotalDebe += (float)$debe;
$sumTotalHaber += (float)$haber;
$numeroTotalPolizas += 1;
}
// Para la última póliza en el loop, también agregamos el MontoTotal
if ($polizaNodo !== null) {
$montoTotal = $totalDebe - $totalHaber;
$polizaNodo->setAttribute("MontoTotal", number_format($montoTotal, 2, '.', '')); // Agregar MontoTotal al final
}
// Establecer el tipo de contenido a XML y devolver el contenido
// header('Content-Type: application/xml; charset=utf-8');
// echo $xml->saveXML();
#=== Se guarda el archivo .XML del Catalogo de Cuentas =======================
$file_name_with_full_path = '/var/www/html/aptusContaElec/archs_xml/'.$RFC.$anio.$mes."PP.xml";
#=== Si existe el archivo XML se elimina para crear el nuevo =======================
if(!file_exists($file_name_with_full_path)){
unlink($file_name_with_full_path);
}
#=== Se guarda el archivo XML creado =======================
$polizaXML = $xml->saveXML();
$xml->formatOutput = true;
$xml->save($file_name_with_full_path);
unset($xml);
#=== Se dan permisos de escritura al archivo .xml. =========================
chmod($file_name_with_full_path, 0777);
#=== Se procede a crear el archivo ZIP del Catalogo de Cuentas =========================
$zip = new ZipArchive();
$nombreArchivoZip = '/var/www/html/aptusContaElec/archs_zip/'.$RFC.$anio.$mes."PP.zip";
$nameArchZip = $RFC.$anio.$mes."PP.zip";
#=== Si existe el archivo ZIP se elimina para crear el nuevo =======================
if(!file_exists($nombreArchivoZip)){
unlink($nombreArchivoZip);
}
if (!$zip->open($nombreArchivoZip, ZipArchive::CREATE | ZipArchive::OVERWRITE)) {
exit("Error abriendo ZIP en $nombreArchivoZip");
}
$nombre = basename($file_name_with_full_path);
$zip->addFile($file_name_with_full_path, $nombre);
$resultado = $zip->close();
if ($resultado) {
} else {
$j_array = array('code' => "318", "message" => "ERROR - [wsPolizasAnalytics] Error al crear el archivo ZIP");
$Resultado = json_encode($j_array);
echo $Resultado;
return $Resultado;
}
#----------------------------------------------------------------
# Se sube archivo ZIP a Workdrive
#----------------------------------------------------------------
$woa_access_token = oauth($appOwner, 'ZWorkrdv', $woa_RefreshToken, $woa_ClientId, $woa_ClientSecret, $woa_RedirectUri, $woa_GrantType, $woa_AuthUrl);
$urlWorkdrv = 'https://workdrive.zoho.com/api/v1/upload?parent_id='.$wdrv_parent_id.'&filename='.$nameArchZip.'&override-name-exist=true';
$curl = curl_init();
curl_setopt_array($curl,
array(
CURLOPT_URL => $urlWorkdrv,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => '',
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 0,
CURLOPT_FOLLOWLOCATION => true,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => 'POST',
CURLOPT_POSTFIELDS => array('content'=> new CURLFILE($nombreArchivoZip)),
CURLOPT_HTTPHEADER => array('Authorization: Zoho-oauthtoken '.$woa_access_token ),
)
);
$response = curl_exec($curl);
curl_close($curl);
#=== FIN DEL PROCESO =======================
$j_array = array('code' => "200", 'message' => "Proceso de creacion de archivo de pólizas del periodo exitoso", 'xml_file_name' => $RFC.$anio.$mes."PP.xml", 'zip_file_name' => $RFC.$anio.$mes."PP.zip",'Total de Polizas' => $numeroTotalPolizas,'Total Debe' =>number_format($sumTotalDebe, 2, '.', ''),'Total Haber' => number_format($sumTotalHaber, 2, '.', ''));
$Resultado = json_encode($j_array);
echo $Resultado;
return $Resultado;
} else {
$j_array = array('code' => "315", "message" => "ERROR - [wsPolizasAnalytics] No se obtuvieron datos de la vista");
$Resultado = json_encode($j_array);
echo $Resultado;
return $Resultado;
}
### FUNCIONES DEL MÓDULO #########################################################
# Función que integra los nodos al archivo .XML
function cargaAttNodo(&$nodo, $attr){
global $xmldoc;
foreach ($attr as $key => $val){
$val = preg_replace('/\s\s+/', ' ', $val);
$val = trim($val);
if (strlen($val)>0){
$val = utf8_encode(str_replace("|","/",$val));
$nodo->setAttribute($key,$val);
}
}
}
function obtenerDiasDelMes($mes) {
// Validar que el parámetro sea una cadena con dos dígitos
if (!preg_match('/^\d{2}$/', $mes)) {
return "Formato de mes inválido.";
}
// Obtener el año actual
$anio = date("Y");
// Usar la función `cal_days_in_month` para obtener la cantidad de días del mes
$dias = cal_days_in_month(CAL_GREGORIAN, intval($mes), $anio);
return $dias;
}